@pasko70/pibo 1.16.6 → 2.0.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/dist/agent-runtime/auth.js +28 -0
- package/dist/agent-runtime/capabilities.js +221 -0
- package/dist/agent-runtime/context-build.js +313 -0
- package/dist/agent-runtime/contract.js +45 -0
- package/dist/agent-runtime/errors.js +57 -0
- package/dist/agent-runtime/events.js +1 -0
- package/dist/agent-runtime/history.js +1 -0
- package/dist/agent-runtime/profile-validation.js +109 -0
- package/dist/agent-runtime/registry.js +608 -0
- package/dist/agent-runtime/resource-files.js +87 -0
- package/dist/agent-runtime/resource-service.js +635 -0
- package/dist/agent-runtime/resources.js +1 -0
- package/dist/agent-runtime/routed-session.js +931 -0
- package/dist/agent-runtime/testing/contract.js +51 -0
- package/dist/agent-runtime/testing/fake-adapter.js +192 -0
- package/dist/agent-runtime/types.js +3 -0
- package/dist/agent-runtimes/codex-native/adapter.js +905 -0
- package/dist/agent-runtimes/codex-native/auth.js +476 -0
- package/dist/agent-runtimes/codex-native/client.js +734 -0
- package/dist/agent-runtimes/codex-native/config.js +152 -0
- package/dist/agent-runtimes/codex-native/history.js +283 -0
- package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
- package/dist/agent-runtimes/codex-native/models.js +581 -0
- package/dist/agent-runtimes/codex-native/process.js +459 -0
- package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
- package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
- package/dist/agent-runtimes/codex-native/redaction.js +31 -0
- package/dist/agent-runtimes/codex-native/requests.js +378 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
- package/dist/agent-runtimes/codex-native/thread.js +388 -0
- package/dist/agent-runtimes/codex-native/turn.js +849 -0
- package/dist/agent-runtimes/pi/adapter.js +653 -0
- package/dist/agent-runtimes/pi/auth.js +455 -0
- package/dist/agent-runtimes/pi/history.js +640 -0
- package/dist/agent-runtimes/pi/model-catalog.js +87 -0
- package/dist/agent-runtimes/pi/routed-session.js +1464 -0
- package/dist/agent-runtimes/pi/runtime.js +534 -0
- package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
- package/dist/apps/chat/agent-profiles.js +40 -23
- package/dist/apps/chat/agent-store.js +111 -64
- package/dist/apps/chat/chat-api-routes.js +1 -1
- package/dist/apps/chat/chat-request-normalizers.js +47 -0
- package/dist/apps/chat/data/chat-data-mappers.js +25 -9
- package/dist/apps/chat/data/history-query-service.js +108 -0
- package/dist/apps/chat/data/session-query-service.js +24 -3
- package/dist/apps/chat/data/timeline-query-service.js +3 -3
- package/dist/apps/chat/model-catalog.js +1 -55
- package/dist/apps/chat/provider-auth-actions.js +171 -23
- package/dist/apps/chat/stream.js +12 -0
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/trace.js +126 -415
- package/dist/apps/chat/web-app.js +582 -157
- package/dist/apps/chat-ui/assets/{dist-BTLtT_Vf.js → dist-9v2ZXT6V.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CMk1aPug.js → dist-B1LVAytl.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CcwA_IWN.js → dist-C6LPDFXU.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DKOthbxr.js → dist-DVtXxfHc.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-ls2I6BIw.js → dist-DW4Qrfbd.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D1rAtRWs.js → dist-DmbsHdMC.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C1JQRskW.js → dist-DyvwuSFO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DfpaylQ-.js → dist-I26VB0QO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D10bTFD5.js → dist-RtHbJRPV.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-5KpmmBBZ.js → dist-sZgJkWZb.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
- package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
- package/dist/auth/login-actions.js +5 -251
- package/dist/cli-session/localSessionSource.js +8 -1
- package/dist/core/context-build.js +124 -20
- package/dist/core/default-profile.js +8 -0
- package/dist/core/profiles.js +30 -3
- package/dist/core/routed-session.js +5 -1446
- package/dist/core/runtime.js +5 -561
- package/dist/core/session-router.js +637 -83
- package/dist/data/cli.js +20 -3
- package/dist/data/schema.js +104 -1
- package/dist/data/session-store.js +24 -1
- package/dist/debug/events.js +25 -10
- package/dist/debug/failures.js +23 -3
- package/dist/debug/index.js +24 -6
- package/dist/debug/messages.js +87 -7
- package/dist/debug/persisted-payloads.js +31 -0
- package/dist/debug/pty.js +7 -6
- package/dist/debug/runtime-binding.js +29 -0
- package/dist/debug/session.js +137 -0
- package/dist/debug/summary.js +12 -0
- package/dist/debug/telemetry.js +28 -0
- package/dist/debug/tools.js +12 -2
- package/dist/debug/trace.js +154 -76
- package/dist/gateway/server.js +87 -2
- package/dist/gateway/tool.js +5 -5
- package/dist/index.js +21 -2
- package/dist/loops/tools.js +13 -12
- package/dist/mcp/agent-context.js +13 -4
- package/dist/mcp/client.js +10 -6
- package/dist/mcp/config.js +5 -2
- package/dist/mcp/runtime-session.js +166 -0
- package/dist/plugins/builtin.js +191 -53
- package/dist/plugins/codex-native.js +29 -0
- package/dist/plugins/registry.js +66 -2
- package/dist/runs/tools.js +26 -25
- package/dist/session-ui/terminalRows.js +2 -2
- package/dist/sessions/pibo-data-store.js +125 -16
- package/dist/sessions/runtime-binding.js +107 -0
- package/dist/sessions/sqlite-store.js +239 -18
- package/dist/sessions/store.js +86 -7
- package/dist/shared/trace-engine.js +18 -9
- package/dist/shared/trace-event-projection.js +29 -11
- package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
- package/dist/shared/trace-order.js +9 -4
- package/dist/shared/trace-page-merge.js +1 -1
- package/dist/signals/projector.js +20 -2
- package/dist/signals/registry.js +11 -0
- package/dist/subagents/tool.js +8 -6
- package/dist/tools/codex-browser.js +20 -19
- package/dist/tools/codex-compat.js +10 -9
- package/dist/tools/codex-image-generation.js +8 -6
- package/dist/tools/contract.js +45 -0
- package/dist/tools/credential-registry.js +182 -0
- package/dist/tools/mcp-bridge.js +511 -0
- package/dist/tools/payload-writer.js +17 -0
- package/dist/tools/runtime/tool.js +10 -9
- package/dist/tools/schema.js +9 -0
- package/dist/tools/session-service.js +193 -0
- package/dist/tools/session-tool-set.js +85 -0
- package/dist/web-annotations/tools.js +17 -16
- package/docs/README.md +11 -0
- package/package.json +3 -2
- package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
- package/dist/apps/chat-ui/assets/index-C2YI0xfw.js +0 -237
- package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
- package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
|
@@ -2,24 +2,28 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import { monitorEventLoopDelay } from "node:perf_hooks";
|
|
4
4
|
import { PiboSteeringUnavailableError } from "../../core/events.js";
|
|
5
|
+
import { PI_AGENT_RUNTIME_CAPABILITIES } from "../../agent-runtimes/pi/adapter.js";
|
|
6
|
+
import { AgentRuntimeBindingMissingError } from "../../agent-runtime/errors.js";
|
|
7
|
+
import { buildPortableRuntimeContextSnapshot, profileWithRuntimeInstance, uniqueRuntimeDiagnostics, } from "../../agent-runtime/context-build.js";
|
|
8
|
+
import { PiboRuntimeResourceService } from "../../agent-runtime/resource-service.js";
|
|
5
9
|
import { summarizeSessionSignalStatus } from "../../signals/status.js";
|
|
6
10
|
import { PiboWebHttpError, readJsonBody, responseJson } from "../../web/http.js";
|
|
7
11
|
import { OutputCompactor } from "./output-compactor.js";
|
|
8
12
|
import { isLiveOnlyOutputEvent, isPersistableOutputEvent } from "./output-event-policy.js";
|
|
9
13
|
import { chatRoomIdFromMetadata, isDefaultPiboRoom, isPiboRoomArchived, roomWorkspaceFromMetadata, withChatRoomId, withPiboRoomWorkspace, } from "./types/rooms.js";
|
|
10
14
|
import { chatStreamFramesFromOutputEvent, createChatStreamState, nextTransientChatStreamFrameId } from "./stream.js";
|
|
11
|
-
import { buildSessionNodes, buildTraceView
|
|
15
|
+
import { buildSessionNodes, buildTraceView } from "./trace.js";
|
|
12
16
|
import { DEFAULT_TRACE_EVENTS_PAGE_SIZE, annotateTracePage, etagForVersion, estimateTraceViewBytes, traceCacheEstimatedBytes, liveSnapshotVersion, requestMatchesVersion, setTraceCache, traceProjectionStatus, traceCacheKey, withLiveSnapshots, withRawTraceTail, } from "./chat-trace-helpers.js";
|
|
13
17
|
import { TRACE_V2_DEFAULT_TIMELINE_LIMIT, TRACE_V2_MAX_TIMELINE_LIMIT, TRACE_V2_PAYLOAD_DEFAULT_LIMIT_BYTES, TRACE_V2_PAYLOAD_MAX_LIMIT_BYTES, TRACE_V2_RAW_EVENTS_DEFAULT_LIMIT, TRACE_V2_RAW_EVENTS_MAX_LIMIT, TRACE_V2_TIMELINE_HARD_BYTES, parseTracePayloadRef, readTracePayloadChunk, traceRawEventsPageFromEvents, traceTimelinePageFromView, } from "./trace-v2.js";
|
|
14
18
|
import { isChatWebSessionArchived } from "./session-metadata.js";
|
|
15
19
|
import { withWorkflowSessionKind } from "../../sessions/workflow-session-kind.js";
|
|
16
|
-
import { CustomAgentStore, createDefaultCustomAgentStore, } from "./agent-store.js";
|
|
20
|
+
import { CustomAgentStore, createDefaultCustomAgentStore, previewCustomAgentCreate, previewCustomAgentUpdate, } from "./agent-store.js";
|
|
17
21
|
import { loadPiboModelDefaults, } from "../../core/model-defaults.js";
|
|
18
22
|
import { inspectPiboContextBuild } from "../../core/context-build.js";
|
|
19
23
|
import { loadPiboUserSettings, updateTelemetryRetentionLastPrunedAt } from "../../core/user-settings.js";
|
|
20
24
|
import { isTelemetryRetentionMaintenanceDue, maybeRunTelemetryRetentionMaintenance } from "./telemetry-retention-service.js";
|
|
21
25
|
import { loadModelCatalog } from "./model-catalog.js";
|
|
22
|
-
import { createCustomAgentProfileDefinition } from "./agent-profiles.js";
|
|
26
|
+
import { createCustomAgentProfileDefinition, createCustomAgentRuntimeValidationProfile } from "./agent-profiles.js";
|
|
23
27
|
import { createDefaultPiboReliabilityStore, PiboReliabilityStore } from "../../reliability/store.js";
|
|
24
28
|
import { listMcpServerInfos } from "../../mcp/agent-context.js";
|
|
25
29
|
import { getDefaultPiboWorkspace } from "../../core/workspace.js";
|
|
@@ -31,6 +35,7 @@ import { ChatReadStateService } from "./data/read-state-service.js";
|
|
|
31
35
|
import { ChatRoomService } from "./data/room-service.js";
|
|
32
36
|
import { ChatSessionQueryService } from "./data/session-query-service.js";
|
|
33
37
|
import { ChatTimelineQueryService } from "./data/timeline-query-service.js";
|
|
38
|
+
import { ChatHistoryQueryService } from "./data/history-query-service.js";
|
|
34
39
|
import { ChatProjectService } from "./data/project-service.js";
|
|
35
40
|
import { PiboDataStore } from "../../data/pibo-store.js";
|
|
36
41
|
import { createDefaultPiboCronStore } from "../../cron/store.js";
|
|
@@ -40,7 +45,7 @@ import { handleChatLoopApiRequest } from "./loop-api.js";
|
|
|
40
45
|
import { prepareWebAnnotationMessageAttachments } from "../../web-annotations/attachments.js";
|
|
41
46
|
import { createDefaultWebAnnotationStore } from "../../web-annotations/store.js";
|
|
42
47
|
import { CHAT_WEB_MOUNT_PATH, isChatAppPath, responseBuiltChatAsset, responseBuiltChatPublicFile, responseChatAppShell, isVscodeAppPath, responseBuiltVscodeAsset, responseVscodeAppShell } from "./static-assets.js";
|
|
43
|
-
import { executeProviderAuthAction, isProviderAuthAction, providerAuthActionResponse } from "./provider-auth-actions.js";
|
|
48
|
+
import { executeProviderAuthAction, isProviderAuthAction, providerAuthActionResponse, readProviderAuthCatalog, } from "./provider-auth-actions.js";
|
|
44
49
|
import { prepareChatFileAttachments, resolveDownloadPath, responseChatFileDownload, saveUploadedChatFiles } from "./chat-files.js";
|
|
45
50
|
import { chatSettingsRoute, chatSettingsRouteInvalidatesBootstrapCatalog, chatSettingsRouteRequiresSameOrigin, handleChatSettingsRoute, } from "./chat-settings-routes.js";
|
|
46
51
|
import { chatCapabilityRoute, chatCapabilityRouteRequiresSameOrigin, handleChatCapabilityRoute, } from "./chat-capability-routes.js";
|
|
@@ -331,6 +336,7 @@ function createFastTraceV2Version(input) {
|
|
|
331
336
|
profile: input.session.profile,
|
|
332
337
|
title: input.session.title ?? null,
|
|
333
338
|
updatedAt: input.session.updatedAt,
|
|
339
|
+
runtimeBinding: traceRuntimeBindingFromSession(input.session),
|
|
334
340
|
},
|
|
335
341
|
status: input.status ?? "idle",
|
|
336
342
|
events: {
|
|
@@ -338,11 +344,13 @@ function createFastTraceV2Version(input) {
|
|
|
338
344
|
lastActivityAt: input.lastActivityAt ?? null,
|
|
339
345
|
latestStreamId: input.latestStreamId ?? null,
|
|
340
346
|
},
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
347
|
+
productHistory: {
|
|
348
|
+
messageCount: input.productHistory?.messageCount ?? 0,
|
|
349
|
+
firstEventSequence: input.productHistory?.firstEventSequence ?? null,
|
|
350
|
+
lastEventSequence: input.productHistory?.lastEventSequence ?? null,
|
|
351
|
+
lastCreatedAt: input.productHistory?.lastCreatedAt ?? null,
|
|
345
352
|
},
|
|
353
|
+
nativeHistoryVersion: input.nativeHistoryVersion ?? null,
|
|
346
354
|
sessions: relevantSessions,
|
|
347
355
|
}))
|
|
348
356
|
.digest("hex");
|
|
@@ -896,6 +904,54 @@ function serializeCustomAgent(agent, context) {
|
|
|
896
904
|
function serializeCustomAgents(agents, context) {
|
|
897
905
|
return agents.map((agent) => serializeCustomAgent(agent, context));
|
|
898
906
|
}
|
|
907
|
+
const RUNTIME_PROFILE_UPDATE_FIELDS = new Set([
|
|
908
|
+
"runtimeInstanceId",
|
|
909
|
+
"runtimeOptions",
|
|
910
|
+
"nativeTools",
|
|
911
|
+
"skills",
|
|
912
|
+
"contextFiles",
|
|
913
|
+
"subagents",
|
|
914
|
+
"mcpServers",
|
|
915
|
+
"piPackages",
|
|
916
|
+
"mainModel",
|
|
917
|
+
"subagentModel",
|
|
918
|
+
"thinkingLevel",
|
|
919
|
+
"mainThinkingLevel",
|
|
920
|
+
"subagentThinkingLevel",
|
|
921
|
+
"fast",
|
|
922
|
+
"mainFast",
|
|
923
|
+
"subagentFast",
|
|
924
|
+
"builtinTools",
|
|
925
|
+
"builtinToolNames",
|
|
926
|
+
"autoContextFiles",
|
|
927
|
+
"runControl",
|
|
928
|
+
"goalControl",
|
|
929
|
+
]);
|
|
930
|
+
function customAgentUpdateAffectsRuntime(update) {
|
|
931
|
+
return Object.keys(update).some((field) => RUNTIME_PROFILE_UPDATE_FIELDS.has(field));
|
|
932
|
+
}
|
|
933
|
+
async function requireValidCustomAgentRuntime(agent, context) {
|
|
934
|
+
const profile = createCustomAgentRuntimeValidationProfile(agent);
|
|
935
|
+
let diagnostics;
|
|
936
|
+
if (context.channelContext.validateAgentRuntimeProfile) {
|
|
937
|
+
diagnostics = await context.channelContext.validateAgentRuntimeProfile(profile, process.cwd());
|
|
938
|
+
}
|
|
939
|
+
else {
|
|
940
|
+
const runtimes = context.channelContext.getCapabilityCatalog?.().agentRuntimes ?? [];
|
|
941
|
+
const selected = runtimes.find((runtime) => runtime.id === agent.runtimeInstanceId);
|
|
942
|
+
if (!selected && runtimes.length === 0 && agent.runtimeInstanceId === "pi")
|
|
943
|
+
return;
|
|
944
|
+
diagnostics = selected
|
|
945
|
+
? selected.enabled
|
|
946
|
+
? []
|
|
947
|
+
: [{ severity: "error", code: "runtime_instance_disabled", message: `Agent runtime instance "${selected.id}" is disabled.` }]
|
|
948
|
+
: [{ severity: "error", code: "runtime_instance_unknown", message: `Unknown agent runtime instance "${agent.runtimeInstanceId}".` }];
|
|
949
|
+
}
|
|
950
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
951
|
+
if (errors.length === 0)
|
|
952
|
+
return;
|
|
953
|
+
throw new PiboWebHttpError(`Agent runtime selection is invalid: ${errors.map((diagnostic) => diagnostic.message).join(" ")}`, 400);
|
|
954
|
+
}
|
|
899
955
|
function listBrokenContextFiles(keys, context) {
|
|
900
956
|
const catalog = context.channelContext.getCapabilityCatalog?.();
|
|
901
957
|
if (!catalog)
|
|
@@ -923,17 +979,48 @@ function requireSharedAgent(agent) {
|
|
|
923
979
|
return agent;
|
|
924
980
|
}
|
|
925
981
|
async function buildAgentCatalog(context, state) {
|
|
982
|
+
const baseCatalog = context.channelContext.getCapabilityCatalog?.() ?? {
|
|
983
|
+
agentRuntimes: [],
|
|
984
|
+
nativeTools: [],
|
|
985
|
+
skills: [],
|
|
986
|
+
subagents: [],
|
|
987
|
+
contextFiles: [],
|
|
988
|
+
packages: [],
|
|
989
|
+
piboTools: [],
|
|
990
|
+
mcpServers: [],
|
|
991
|
+
piPackages: [],
|
|
992
|
+
};
|
|
993
|
+
let agentRuntimes = (baseCatalog.agentRuntimes ?? []).map((runtime) => {
|
|
994
|
+
const diagnostics = runtime.enabled ? [] : [{
|
|
995
|
+
severity: "error",
|
|
996
|
+
code: "runtime_instance_disabled",
|
|
997
|
+
message: `Agent runtime instance "${runtime.id}" is disabled.`,
|
|
998
|
+
}];
|
|
999
|
+
return {
|
|
1000
|
+
...runtime,
|
|
1001
|
+
available: runtime.enabled,
|
|
1002
|
+
diagnostics,
|
|
1003
|
+
};
|
|
1004
|
+
});
|
|
1005
|
+
if (context.channelContext.inspectAgentRuntimeInstances) {
|
|
1006
|
+
try {
|
|
1007
|
+
agentRuntimes = await context.channelContext.inspectAgentRuntimeInstances();
|
|
1008
|
+
}
|
|
1009
|
+
catch (error) {
|
|
1010
|
+
agentRuntimes = agentRuntimes.map((runtime) => ({
|
|
1011
|
+
...runtime,
|
|
1012
|
+
available: false,
|
|
1013
|
+
diagnostics: [{
|
|
1014
|
+
severity: "error",
|
|
1015
|
+
code: "runtime_catalog_diagnostics_failed",
|
|
1016
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1017
|
+
}],
|
|
1018
|
+
}));
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
926
1021
|
return {
|
|
927
|
-
...
|
|
928
|
-
|
|
929
|
-
skills: [],
|
|
930
|
-
subagents: [],
|
|
931
|
-
contextFiles: [],
|
|
932
|
-
packages: [],
|
|
933
|
-
piboTools: [],
|
|
934
|
-
mcpServers: [],
|
|
935
|
-
piPackages: [],
|
|
936
|
-
}),
|
|
1022
|
+
...baseCatalog,
|
|
1023
|
+
agentRuntimes,
|
|
937
1024
|
mcpServers: await listMcpServerInfos(),
|
|
938
1025
|
piPackages: listPiPackages(),
|
|
939
1026
|
userSkills: state.userSkillManager.list(),
|
|
@@ -2036,7 +2123,7 @@ function normalizeAgentDeleteConfirmation(value) {
|
|
|
2036
2123
|
}
|
|
2037
2124
|
return value.trim();
|
|
2038
2125
|
}
|
|
2039
|
-
function deleteSessionsForAgentProfile(state, context, webSession, profileNames) {
|
|
2126
|
+
async function deleteSessionsForAgentProfile(state, context, webSession, profileNames) {
|
|
2040
2127
|
const deleteSession = context.channelContext.deleteSession;
|
|
2041
2128
|
if (!deleteSession)
|
|
2042
2129
|
throw new PiboWebHttpError("Session deletion is not available", 501);
|
|
@@ -2055,13 +2142,13 @@ function deleteSessionsForAgentProfile(state, context, webSession, profileNames)
|
|
|
2055
2142
|
}
|
|
2056
2143
|
}
|
|
2057
2144
|
const orderedIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
|
|
2145
|
+
for (const id of orderedIds)
|
|
2146
|
+
await deleteSession(id);
|
|
2058
2147
|
state.sessionQuery.deleteSessions(orderedIds);
|
|
2059
2148
|
state.eventCommands.deleteSessions(orderedIds);
|
|
2060
|
-
for (const id of orderedIds)
|
|
2061
|
-
deleteSession(id);
|
|
2062
2149
|
return orderedIds;
|
|
2063
2150
|
}
|
|
2064
|
-
function deleteSessionSubtree(state, context, webSession, rootSession) {
|
|
2151
|
+
async function deleteSessionSubtree(state, context, webSession, rootSession) {
|
|
2065
2152
|
const deleteSession = context.channelContext.deleteSession;
|
|
2066
2153
|
if (!deleteSession)
|
|
2067
2154
|
throw new PiboWebHttpError("Session deletion is not available", 501);
|
|
@@ -2079,13 +2166,13 @@ function deleteSessionSubtree(state, context, webSession, rootSession) {
|
|
|
2079
2166
|
}
|
|
2080
2167
|
}
|
|
2081
2168
|
const orderedIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
|
|
2169
|
+
for (const id of orderedIds)
|
|
2170
|
+
await deleteSession(id);
|
|
2082
2171
|
state.sessionQuery.deleteSessions(orderedIds);
|
|
2083
2172
|
state.eventCommands.deleteSessions(orderedIds);
|
|
2084
|
-
for (const id of orderedIds)
|
|
2085
|
-
deleteSession(id);
|
|
2086
2173
|
return orderedIds;
|
|
2087
2174
|
}
|
|
2088
|
-
function deleteRoomTree(state, context, webSession, room, confirmName) {
|
|
2175
|
+
async function deleteRoomTree(state, context, webSession, room, confirmName) {
|
|
2089
2176
|
if (isDefaultPiboRoom(room))
|
|
2090
2177
|
throw new PiboWebHttpError("Default chat cannot be deleted", 400);
|
|
2091
2178
|
if (!isPiboRoomArchived(room))
|
|
@@ -2117,11 +2204,11 @@ function deleteRoomTree(state, context, webSession, room, confirmName) {
|
|
|
2117
2204
|
}
|
|
2118
2205
|
}
|
|
2119
2206
|
const orderedSessionIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
|
|
2207
|
+
for (const id of orderedSessionIds)
|
|
2208
|
+
await deleteSession(id);
|
|
2120
2209
|
state.sessionQuery.deleteSessions(orderedSessionIds);
|
|
2121
2210
|
state.eventCommands.deleteSessions(orderedSessionIds);
|
|
2122
2211
|
state.eventCommands.deleteRooms(roomIds);
|
|
2123
|
-
for (const id of orderedSessionIds)
|
|
2124
|
-
deleteSession(id);
|
|
2125
2212
|
const orderedRoomIds = [...roomIds].reverse();
|
|
2126
2213
|
state.roomService.deleteRooms(orderedRoomIds);
|
|
2127
2214
|
return { deletedRoomIds: orderedRoomIds, deletedSessionIds: orderedSessionIds };
|
|
@@ -2142,6 +2229,29 @@ function requireSharedSession(context, piboSessionId) {
|
|
|
2142
2229
|
}
|
|
2143
2230
|
return canonicalizeSessionProfile(context, session);
|
|
2144
2231
|
}
|
|
2232
|
+
function defaultRuntimeInstanceId(context, defaultProfile) {
|
|
2233
|
+
if (context.channelContext.createProfile) {
|
|
2234
|
+
try {
|
|
2235
|
+
return context.channelContext.createProfile(defaultProfile).runtimeInstanceId;
|
|
2236
|
+
}
|
|
2237
|
+
catch {
|
|
2238
|
+
// Fall through to the registered runtime order when the profile is unavailable.
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
return context.channelContext.getCapabilityCatalog?.().agentRuntimes?.[0]?.id;
|
|
2242
|
+
}
|
|
2243
|
+
function sessionRuntimeInstanceId(context, session) {
|
|
2244
|
+
return context.channelContext.getSessionRuntimeBinding?.(session.id)?.runtimeInstanceId
|
|
2245
|
+
?? session.runtimeBinding?.runtimeInstanceId
|
|
2246
|
+
?? (() => {
|
|
2247
|
+
try {
|
|
2248
|
+
return context.channelContext.createProfile?.(session.profile).runtimeInstanceId;
|
|
2249
|
+
}
|
|
2250
|
+
catch {
|
|
2251
|
+
return undefined;
|
|
2252
|
+
}
|
|
2253
|
+
})();
|
|
2254
|
+
}
|
|
2145
2255
|
function resolveRequestedSession(state, context, webSession, defaultProfile, piboSessionId, roomId) {
|
|
2146
2256
|
if (!piboSessionId)
|
|
2147
2257
|
return ensureDefaultChatSession(state, context, webSession, defaultProfile, roomId);
|
|
@@ -2162,20 +2272,125 @@ async function buildContextBuildSnapshotForRequest(input) {
|
|
|
2162
2272
|
if (!input.piboSessionId)
|
|
2163
2273
|
throw new PiboWebHttpError("piboSessionId is required", 400);
|
|
2164
2274
|
const selectedSession = requireSharedSession(input.context, input.piboSessionId);
|
|
2165
|
-
const
|
|
2275
|
+
const configuredProfile = createProfile(selectedSession.profile);
|
|
2276
|
+
const runtimeInstanceId = selectedSession.runtimeBinding?.runtimeInstanceId ?? configuredProfile.runtimeInstanceId;
|
|
2277
|
+
const profile = profileWithRuntimeInstance(configuredProfile, runtimeInstanceId);
|
|
2278
|
+
const cwd = selectedSession.workspace ?? getDefaultPiboWorkspace();
|
|
2279
|
+
const runtime = await resolveContextBuildRuntime(input.context, runtimeInstanceId);
|
|
2280
|
+
const validationDiagnostics = input.context.channelContext.validateAgentRuntimeProfile
|
|
2281
|
+
? await input.context.channelContext.validateAgentRuntimeProfile(profile, cwd)
|
|
2282
|
+
: [];
|
|
2283
|
+
const bindingMismatchDiagnostic = selectedSession.runtimeBinding && selectedSession.runtimeBinding.adapterId !== runtime.adapterId
|
|
2284
|
+
? [{
|
|
2285
|
+
severity: "error",
|
|
2286
|
+
code: "runtime_binding_adapter_mismatch",
|
|
2287
|
+
message: `Session binding expects adapter "${selectedSession.runtimeBinding.adapterId}", but runtime instance "${runtime.id}" uses "${runtime.adapterId}".`,
|
|
2288
|
+
}]
|
|
2289
|
+
: [];
|
|
2290
|
+
const diagnostics = uniqueRuntimeDiagnostics([
|
|
2291
|
+
...runtime.diagnostics,
|
|
2292
|
+
...validationDiagnostics,
|
|
2293
|
+
...bindingMismatchDiagnostic,
|
|
2294
|
+
]);
|
|
2295
|
+
const runtimeInfo = {
|
|
2296
|
+
runtimeInstanceId: runtime.id,
|
|
2297
|
+
adapterId: runtime.adapterId,
|
|
2298
|
+
available: runtime.available && !diagnostics.some((diagnostic) => diagnostic.severity === "error"),
|
|
2299
|
+
transport: runtime.transport,
|
|
2300
|
+
bindingState: selectedSession.runtimeBinding?.state,
|
|
2301
|
+
protocol: runtime.protocol,
|
|
2302
|
+
capabilities: runtime.capabilities,
|
|
2303
|
+
diagnostics,
|
|
2304
|
+
};
|
|
2166
2305
|
const userSettings = loadPiboUserSettings();
|
|
2167
|
-
const
|
|
2168
|
-
|
|
2169
|
-
|
|
2306
|
+
const resourceService = new PiboRuntimeResourceService();
|
|
2307
|
+
const resources = await resourceService.createSession({
|
|
2308
|
+
piboSessionId: selectedSession.id,
|
|
2309
|
+
piboRoomId: chatRoomIdFromMetadata(selectedSession.metadata),
|
|
2310
|
+
runtimeInstanceId: runtime.id,
|
|
2311
|
+
adapterId: runtime.adapterId,
|
|
2312
|
+
sessionGeneration: `inspection-${randomUUID()}`,
|
|
2170
2313
|
profile,
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
piboRoomId: selectedSession ? chatRoomIdFromMetadata(selectedSession.metadata) : undefined,
|
|
2176
|
-
timezone: userSettings.timezone,
|
|
2177
|
-
},
|
|
2314
|
+
cwd,
|
|
2315
|
+
timezone: userSettings.timezone,
|
|
2316
|
+
capabilities: runtime.capabilities,
|
|
2317
|
+
strict: false,
|
|
2178
2318
|
});
|
|
2319
|
+
try {
|
|
2320
|
+
if (runtime.adapterId === "pi" && runtimeInfo.available) {
|
|
2321
|
+
const snapshot = await inspectPiboContextBuild({
|
|
2322
|
+
cwd,
|
|
2323
|
+
profile,
|
|
2324
|
+
activeModel: selectedSession.activeModel,
|
|
2325
|
+
persistSession: false,
|
|
2326
|
+
resources,
|
|
2327
|
+
sessionContext: {
|
|
2328
|
+
piboSessionId: selectedSession.id,
|
|
2329
|
+
piboRoomId: chatRoomIdFromMetadata(selectedSession.metadata),
|
|
2330
|
+
timezone: userSettings.timezone,
|
|
2331
|
+
},
|
|
2332
|
+
});
|
|
2333
|
+
const runtimeIssues = diagnostics.filter((diagnostic) => diagnostic.severity !== "info");
|
|
2334
|
+
return {
|
|
2335
|
+
...snapshot,
|
|
2336
|
+
runtime: runtimeInfo,
|
|
2337
|
+
diagnostics: [
|
|
2338
|
+
...snapshot.diagnostics,
|
|
2339
|
+
...runtimeIssues.map((diagnostic) => ({ type: diagnostic.severity, message: diagnostic.message })),
|
|
2340
|
+
],
|
|
2341
|
+
summary: {
|
|
2342
|
+
...snapshot.summary,
|
|
2343
|
+
warnings: snapshot.summary.warnings + runtimeIssues.filter((diagnostic) => diagnostic.severity === "warning").length,
|
|
2344
|
+
errors: snapshot.summary.errors + runtimeIssues.filter((diagnostic) => diagnostic.severity === "error").length,
|
|
2345
|
+
},
|
|
2346
|
+
};
|
|
2347
|
+
}
|
|
2348
|
+
return buildPortableRuntimeContextSnapshot({
|
|
2349
|
+
profile,
|
|
2350
|
+
runtime: runtimeInfo,
|
|
2351
|
+
cwd,
|
|
2352
|
+
piboSessionId: selectedSession.id,
|
|
2353
|
+
piboRoomId: chatRoomIdFromMetadata(selectedSession.metadata),
|
|
2354
|
+
activeModel: selectedSession.activeModel,
|
|
2355
|
+
resources: resources.getInspection(),
|
|
2356
|
+
});
|
|
2357
|
+
}
|
|
2358
|
+
finally {
|
|
2359
|
+
await resourceService.dispose();
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
async function resolveContextBuildRuntime(context, runtimeInstanceId) {
|
|
2363
|
+
if (context.channelContext.inspectAgentRuntimeInstances) {
|
|
2364
|
+
const runtime = (await context.channelContext.inspectAgentRuntimeInstances()).find((candidate) => candidate.id === runtimeInstanceId);
|
|
2365
|
+
if (runtime)
|
|
2366
|
+
return runtime;
|
|
2367
|
+
}
|
|
2368
|
+
const runtime = context.channelContext.getCapabilityCatalog?.().agentRuntimes?.find((candidate) => candidate.id === runtimeInstanceId);
|
|
2369
|
+
if (!runtime && runtimeInstanceId === "pi") {
|
|
2370
|
+
return {
|
|
2371
|
+
id: "pi",
|
|
2372
|
+
adapterId: "pi",
|
|
2373
|
+
displayName: "Pi Coding Agent",
|
|
2374
|
+
enabled: true,
|
|
2375
|
+
available: true,
|
|
2376
|
+
transport: "embedded",
|
|
2377
|
+
capabilities: structuredClone(PI_AGENT_RUNTIME_CAPABILITIES),
|
|
2378
|
+
configSchema: { type: "object", additionalProperties: false },
|
|
2379
|
+
protocol: { name: "pi-sdk", supportedRange: "0.80.6" },
|
|
2380
|
+
diagnostics: [],
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
if (!runtime)
|
|
2384
|
+
throw new PiboWebHttpError(`Unknown agent runtime instance "${runtimeInstanceId}"`, 400);
|
|
2385
|
+
return {
|
|
2386
|
+
...runtime,
|
|
2387
|
+
available: runtime.enabled,
|
|
2388
|
+
diagnostics: runtime.enabled ? [] : [{
|
|
2389
|
+
severity: "error",
|
|
2390
|
+
code: "runtime_instance_disabled",
|
|
2391
|
+
message: `Agent runtime instance "${runtime.id}" is disabled.`,
|
|
2392
|
+
}],
|
|
2393
|
+
};
|
|
2179
2394
|
}
|
|
2180
2395
|
function indexSharedSessions(sessionQuery, sessions) {
|
|
2181
2396
|
sessionQuery.upsertSessionsIfChanged(sessions);
|
|
@@ -2369,63 +2584,106 @@ function parseTimelineBeforeCursor(url) {
|
|
|
2369
2584
|
const cursor = url.searchParams.get("before") ?? url.searchParams.get("cursor");
|
|
2370
2585
|
if (!cursor || cursor === "tail")
|
|
2371
2586
|
return { kind: "tail" };
|
|
2372
|
-
const
|
|
2373
|
-
if (
|
|
2374
|
-
return
|
|
2587
|
+
const history = parseRuntimeHistoryTimelineCursor(cursor);
|
|
2588
|
+
if (history)
|
|
2589
|
+
return history;
|
|
2375
2590
|
const parsed = Number.parseInt(cursor, 10);
|
|
2376
2591
|
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
2377
|
-
throw new PiboWebHttpError("Trace cursor must be tail,
|
|
2592
|
+
throw new PiboWebHttpError("Trace cursor must be tail, runtime-history, or a positive sequence", 400);
|
|
2378
2593
|
return { kind: "event", beforeSequence: parsed, raw: String(parsed) };
|
|
2379
2594
|
}
|
|
2380
|
-
function
|
|
2381
|
-
if (
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
const beforeByte = Number.parseInt(byteValue ?? "", 10);
|
|
2385
|
-
if (!Number.isFinite(beforeByte) || beforeByte < 0)
|
|
2386
|
-
throw new PiboWebHttpError("Invalid transcript trace cursor", 400);
|
|
2387
|
-
let beforeTimestamp;
|
|
2388
|
-
if (encodedTimestamp) {
|
|
2595
|
+
function parseRuntimeHistoryTimelineCursor(cursor) {
|
|
2596
|
+
if (cursor.startsWith("transcript:")) {
|
|
2597
|
+
const [, , encodedTimestamp] = cursor.split(":");
|
|
2598
|
+
let beforeTimestamp;
|
|
2389
2599
|
try {
|
|
2390
|
-
|
|
2391
|
-
if (decoded)
|
|
2392
|
-
beforeTimestamp = decoded;
|
|
2600
|
+
beforeTimestamp = encodedTimestamp ? Buffer.from(encodedTimestamp, "base64url").toString("utf8") || undefined : undefined;
|
|
2393
2601
|
}
|
|
2394
2602
|
catch {
|
|
2395
|
-
throw new PiboWebHttpError("Invalid transcript trace cursor", 400);
|
|
2603
|
+
throw new PiboWebHttpError("Invalid legacy transcript trace cursor", 400);
|
|
2604
|
+
}
|
|
2605
|
+
return { kind: "history", providerCursor: cursor, beforeTimestamp, raw: cursor };
|
|
2606
|
+
}
|
|
2607
|
+
if (!cursor.startsWith("runtime-history:"))
|
|
2608
|
+
return undefined;
|
|
2609
|
+
try {
|
|
2610
|
+
const payload = JSON.parse(Buffer.from(cursor.slice("runtime-history:".length), "base64url").toString("utf8"));
|
|
2611
|
+
if (payload.v !== 1)
|
|
2612
|
+
throw new Error("unsupported version");
|
|
2613
|
+
for (const value of [payload.piboSessionId, payload.runtimeInstanceId, payload.adapterId, payload.providerCursor, payload.beforeTimestamp]) {
|
|
2614
|
+
if (value !== undefined && typeof value !== "string")
|
|
2615
|
+
throw new Error("invalid field");
|
|
2396
2616
|
}
|
|
2617
|
+
return { kind: "history", ...payload, raw: cursor };
|
|
2618
|
+
}
|
|
2619
|
+
catch (error) {
|
|
2620
|
+
throw new PiboWebHttpError(`Invalid runtime history trace cursor: ${error instanceof Error ? error.message : String(error)}`, 400);
|
|
2397
2621
|
}
|
|
2398
|
-
return { kind: "transcript", beforeByte, beforeTimestamp, raw: cursor };
|
|
2399
2622
|
}
|
|
2400
|
-
function
|
|
2401
|
-
const
|
|
2402
|
-
|
|
2623
|
+
function encodeRuntimeHistoryTimelineCursor(session, input = {}) {
|
|
2624
|
+
const binding = session.runtimeBinding;
|
|
2625
|
+
const payload = {
|
|
2626
|
+
v: 1,
|
|
2627
|
+
piboSessionId: session.id,
|
|
2628
|
+
runtimeInstanceId: binding?.runtimeInstanceId,
|
|
2629
|
+
adapterId: binding?.adapterId,
|
|
2630
|
+
providerCursor: input.providerCursor,
|
|
2631
|
+
beforeTimestamp: input.beforeTimestamp,
|
|
2632
|
+
};
|
|
2633
|
+
return `runtime-history:${Buffer.from(JSON.stringify(payload), "utf8").toString("base64url")}`;
|
|
2634
|
+
}
|
|
2635
|
+
function validateRuntimeHistoryCursor(session, cursor) {
|
|
2636
|
+
const binding = session.runtimeBinding;
|
|
2637
|
+
if (cursor.piboSessionId && cursor.piboSessionId !== session.id) {
|
|
2638
|
+
throw new PiboWebHttpError("Runtime history cursor belongs to a different Pibo session", 409);
|
|
2639
|
+
}
|
|
2640
|
+
if (cursor.runtimeInstanceId && cursor.runtimeInstanceId !== binding?.runtimeInstanceId) {
|
|
2641
|
+
throw new PiboWebHttpError("Runtime history cursor belongs to a different runtime instance", 409);
|
|
2642
|
+
}
|
|
2643
|
+
if (cursor.adapterId && cursor.adapterId !== binding?.adapterId) {
|
|
2644
|
+
throw new PiboWebHttpError("Runtime history cursor belongs to a different runtime adapter", 409);
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
function traceRuntimeBindingFromSession(session) {
|
|
2648
|
+
const binding = session.runtimeBinding;
|
|
2649
|
+
return binding ? {
|
|
2650
|
+
runtimeInstanceId: binding.runtimeInstanceId,
|
|
2651
|
+
adapterId: binding.adapterId,
|
|
2652
|
+
nativeSessionId: binding.nativeSessionId,
|
|
2653
|
+
state: binding.state,
|
|
2654
|
+
protocol: binding.protocol,
|
|
2655
|
+
protocolVersion: binding.protocolVersion,
|
|
2656
|
+
adapterVersion: binding.adapterVersion,
|
|
2657
|
+
revision: binding.revision,
|
|
2658
|
+
} : undefined;
|
|
2659
|
+
}
|
|
2660
|
+
function requiresNativeHistoryCompatibility(session) {
|
|
2661
|
+
const metadata = session.runtimeBinding?.metadata;
|
|
2662
|
+
return session.originId !== undefined
|
|
2663
|
+
|| metadata?.nativeHistoryFallback === true
|
|
2664
|
+
|| typeof metadata?.migrationSource === "string";
|
|
2665
|
+
}
|
|
2666
|
+
function sessionNodeHistoryOptions(context) {
|
|
2667
|
+
return {
|
|
2668
|
+
loadHistoryInspection: async (session) => requiresNativeHistoryCompatibility(session) && context.channelContext.inspectSessionRuntimeHistory
|
|
2669
|
+
? await context.channelContext.inspectSessionRuntimeHistory(session.id).catch(() => undefined)
|
|
2670
|
+
: undefined,
|
|
2671
|
+
};
|
|
2672
|
+
}
|
|
2673
|
+
function runtimeHistorySupported(context, session) {
|
|
2674
|
+
if (!context.channelContext.readSessionRuntimeHistory)
|
|
2675
|
+
return false;
|
|
2676
|
+
const runtimeInstanceId = session.runtimeBinding?.runtimeInstanceId;
|
|
2677
|
+
if (!runtimeInstanceId)
|
|
2678
|
+
return false;
|
|
2679
|
+
return context.channelContext.getCapabilityCatalog?.().agentRuntimes.find((runtime) => runtime.id === runtimeInstanceId)?.capabilities.maintenance.history === true;
|
|
2403
2680
|
}
|
|
2404
2681
|
function compactionCutoffTimestamp(events) {
|
|
2405
2682
|
const compaction = events.find((event) => event.type === "execution_result" && event.payload.type === "execution_result" && event.payload.action === "compact")
|
|
2406
2683
|
?? events.find((event) => event.type === "compaction_end" || event.type === "compaction_start");
|
|
2407
2684
|
return compaction?.createdAt;
|
|
2408
2685
|
}
|
|
2409
|
-
function
|
|
2410
|
-
if (!input.session.originId)
|
|
2411
|
-
return undefined;
|
|
2412
|
-
const sessionPath = input.metadata?.sessionPath;
|
|
2413
|
-
const sessionSize = input.metadata?.sessionSize;
|
|
2414
|
-
if (!sessionPath || !sessionSize || sessionSize <= 0)
|
|
2415
|
-
return undefined;
|
|
2416
|
-
const firstVisibleTranscript = firstVisibleTailTranscriptNode(input.trace.nodes, input.limit);
|
|
2417
|
-
if (!firstVisibleTranscript?.startedAt)
|
|
2418
|
-
return undefined;
|
|
2419
|
-
const probe = readTranscriptHistoryPage(sessionPath, {
|
|
2420
|
-
beforeByte: sessionSize,
|
|
2421
|
-
beforeTimestamp: firstVisibleTranscript.startedAt,
|
|
2422
|
-
limit: 1,
|
|
2423
|
-
});
|
|
2424
|
-
if (probe.entries.length === 0)
|
|
2425
|
-
return undefined;
|
|
2426
|
-
return encodeTranscriptTimelineCursor(sessionSize, firstVisibleTranscript.startedAt);
|
|
2427
|
-
}
|
|
2428
|
-
function firstVisibleTailTranscriptNode(nodes, limit) {
|
|
2686
|
+
function firstVisibleTailHistoryNode(nodes, limit) {
|
|
2429
2687
|
const flat = [];
|
|
2430
2688
|
const visit = (items) => {
|
|
2431
2689
|
for (const item of items) {
|
|
@@ -2434,7 +2692,7 @@ function firstVisibleTailTranscriptNode(nodes, limit) {
|
|
|
2434
2692
|
}
|
|
2435
2693
|
};
|
|
2436
2694
|
visit(nodes);
|
|
2437
|
-
return flat.slice(-Math.max(1, limit)).find((node) => node.source === "transcript" && node.startedAt);
|
|
2695
|
+
return flat.slice(-Math.max(1, limit)).find((node) => (node.source === "transcript" || node.source === "product-history") && node.startedAt);
|
|
2438
2696
|
}
|
|
2439
2697
|
function transientReplayScopeKeys(input) {
|
|
2440
2698
|
const keys = [];
|
|
@@ -2855,7 +3113,7 @@ async function sendProjectMessage(input) {
|
|
|
2855
3113
|
return responseJson({ accepted, output });
|
|
2856
3114
|
}
|
|
2857
3115
|
catch (error) {
|
|
2858
|
-
if (error instanceof PiboSteeringUnavailableError) {
|
|
3116
|
+
if (error instanceof PiboSteeringUnavailableError || error instanceof AgentRuntimeBindingMissingError) {
|
|
2859
3117
|
throw new PiboWebHttpError(error.message, 409);
|
|
2860
3118
|
}
|
|
2861
3119
|
throw error;
|
|
@@ -3057,7 +3315,7 @@ async function sendChatMessage(input) {
|
|
|
3057
3315
|
});
|
|
3058
3316
|
for (const listener of input.state.liveListeners)
|
|
3059
3317
|
listener(failed);
|
|
3060
|
-
if (error instanceof PiboSteeringUnavailableError) {
|
|
3318
|
+
if (error instanceof PiboSteeringUnavailableError || error instanceof AgentRuntimeBindingMissingError) {
|
|
3061
3319
|
throw new PiboWebHttpError(error.message, 409);
|
|
3062
3320
|
}
|
|
3063
3321
|
throw error;
|
|
@@ -3073,6 +3331,7 @@ export function createChatWebApp(options = {}) {
|
|
|
3073
3331
|
const state = {
|
|
3074
3332
|
sessionQuery: new ChatSessionQueryService(dataStore),
|
|
3075
3333
|
timelineQuery: new ChatTimelineQueryService(dataStore),
|
|
3334
|
+
historyQuery: new ChatHistoryQueryService(dataStore),
|
|
3076
3335
|
eventCommands: new ChatEventCommandService(dataStore),
|
|
3077
3336
|
readState: new ChatReadStateService(dataStore),
|
|
3078
3337
|
roomService: new ChatRoomService(dataStore),
|
|
@@ -3227,7 +3486,7 @@ export function createChatWebApp(options = {}) {
|
|
|
3227
3486
|
indexSharedSessions(state.sessionQuery, roomSessions);
|
|
3228
3487
|
const sessionUnreadCounts = buildSessionUnreadCounts(state, ownedSessions);
|
|
3229
3488
|
const [sessions, catalog] = await Promise.all([
|
|
3230
|
-
buildSessionNodes(roomSessions, sessionIndexItemsWithSignalState(context, roomSessions, state.sessionQuery.listSessions(), sessionUnreadCounts), process.cwd(), sessionUnreadCounts),
|
|
3489
|
+
buildSessionNodes(roomSessions, sessionIndexItemsWithSignalState(context, roomSessions, state.sessionQuery.listSessions(), sessionUnreadCounts), process.cwd(), sessionUnreadCounts, sessionNodeHistoryOptions(context)),
|
|
3231
3490
|
loadBootstrapCatalog(state, context, webSession),
|
|
3232
3491
|
]);
|
|
3233
3492
|
const roomTree = state.roomService.listRoomTree();
|
|
@@ -3988,6 +4247,7 @@ export function createChatWebApp(options = {}) {
|
|
|
3988
4247
|
const body = await readJsonBody(request);
|
|
3989
4248
|
const input = createAgentInput(body);
|
|
3990
4249
|
requireAgentProfileNameAvailable(state, context, input.displayName);
|
|
4250
|
+
await requireValidCustomAgentRuntime(previewCustomAgentCreate(input), context);
|
|
3991
4251
|
const agent = state.agentStore.create(input);
|
|
3992
4252
|
context.channelContext.upsertProfile?.(createCustomAgentProfileDefinition(agent));
|
|
3993
4253
|
invalidateBootstrapCatalogCache(state);
|
|
@@ -4003,6 +4263,9 @@ export function createChatWebApp(options = {}) {
|
|
|
4003
4263
|
const archived = normalizeAgentArchived(body.archived);
|
|
4004
4264
|
if (update.displayName)
|
|
4005
4265
|
requireAgentProfileNameAvailable(state, context, update.displayName, existing.id);
|
|
4266
|
+
if (customAgentUpdateAffectsRuntime(update)) {
|
|
4267
|
+
await requireValidCustomAgentRuntime(previewCustomAgentUpdate(existing, update), context);
|
|
4268
|
+
}
|
|
4006
4269
|
const updated = Object.keys(update).length ? state.agentStore.update(patchAgentId, update) : existing;
|
|
4007
4270
|
const afterUpdate = requireSharedAgent(updated);
|
|
4008
4271
|
const agent = archived === undefined ? afterUpdate : state.agentStore.setArchived(patchAgentId, archived);
|
|
@@ -4029,7 +4292,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4029
4292
|
if (confirmName !== agent.profileName) {
|
|
4030
4293
|
throw new PiboWebHttpError(`Type "${agent.profileName}" to permanently delete this agent and its sessions.`, 400);
|
|
4031
4294
|
}
|
|
4032
|
-
const deletedSessionIds = deleteSessionsForAgentProfile(state, context, webSession, [agent.profileName, ...agent.profileAliases]);
|
|
4295
|
+
const deletedSessionIds = await deleteSessionsForAgentProfile(state, context, webSession, [agent.profileName, ...agent.profileAliases]);
|
|
4033
4296
|
state.agentStore.delete(agent.id);
|
|
4034
4297
|
context.channelContext.removeProfile?.(agent.profileName);
|
|
4035
4298
|
invalidateBootstrapCatalogCache(state);
|
|
@@ -4069,7 +4332,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4069
4332
|
includeArchived,
|
|
4070
4333
|
});
|
|
4071
4334
|
indexSharedSessions(state.sessionQuery, roomSessions);
|
|
4072
|
-
const nodes = await buildSessionNodes(roomSessions, state.sessionQuery.listSessions(), process.cwd(), new Map());
|
|
4335
|
+
const nodes = await buildSessionNodes(roomSessions, state.sessionQuery.listSessions(), process.cwd(), new Map(), sessionNodeHistoryOptions(context));
|
|
4073
4336
|
if (!wantsPage)
|
|
4074
4337
|
return responseJson(nodes);
|
|
4075
4338
|
const page = paginateSessionNodes(nodes, { archived: archivedPage, cursor, limit });
|
|
@@ -4130,7 +4393,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4130
4393
|
indexSharedSessions(state.sessionQuery, ownedSessions);
|
|
4131
4394
|
return responseJson({
|
|
4132
4395
|
room,
|
|
4133
|
-
sessions: await buildSessionNodes(ownedSessions, state.sessionQuery.listSessions(), process.cwd(), new Map()),
|
|
4396
|
+
sessions: await buildSessionNodes(ownedSessions, state.sessionQuery.listSessions(), process.cwd(), new Map(), sessionNodeHistoryOptions(context)),
|
|
4134
4397
|
});
|
|
4135
4398
|
}
|
|
4136
4399
|
if (roomResource && roomResource.child === undefined && request.method === "PATCH") {
|
|
@@ -4151,7 +4414,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4151
4414
|
const webSession = await requireSession(request, context);
|
|
4152
4415
|
const room = requireRoom(state, roomResource.roomId, webSession, "admin");
|
|
4153
4416
|
const body = await readJsonBody(request);
|
|
4154
|
-
const deleted = deleteRoomTree(state, context, webSession, room, normalizeRoomDeleteConfirmation(body.confirmName));
|
|
4417
|
+
const deleted = await deleteRoomTree(state, context, webSession, room, normalizeRoomDeleteConfirmation(body.confirmName));
|
|
4155
4418
|
return responseJson(deleted);
|
|
4156
4419
|
}
|
|
4157
4420
|
if (roomResource && roomResource.child === "events" && request.method === "GET") {
|
|
@@ -4196,6 +4459,62 @@ export function createChatWebApp(options = {}) {
|
|
|
4196
4459
|
markSessionsRead(state, sessionSubtree(listSharedSessions(context), selectedSession.id));
|
|
4197
4460
|
return responseJson({ ok: true, piboSessionId: selectedSession.id });
|
|
4198
4461
|
}
|
|
4462
|
+
if (sessionAction?.action === "runtime-binding" && request.method === "GET") {
|
|
4463
|
+
const webSession = await requireSession(request, context);
|
|
4464
|
+
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, sessionAction.piboSessionId);
|
|
4465
|
+
const binding = context.channelContext.getSessionRuntimeBinding?.(selectedSession.id) ?? selectedSession.runtimeBinding;
|
|
4466
|
+
if (!binding)
|
|
4467
|
+
throw new PiboWebHttpError("Runtime binding not found", 404);
|
|
4468
|
+
return responseJson({ binding });
|
|
4469
|
+
}
|
|
4470
|
+
if (sessionAction?.action === "runtime-binding" && request.method === "PATCH") {
|
|
4471
|
+
requireSameOriginJsonRequest(request);
|
|
4472
|
+
const webSession = await requireSession(request, context);
|
|
4473
|
+
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, sessionAction.piboSessionId);
|
|
4474
|
+
if (!context.channelContext.rebindSessionRuntime) {
|
|
4475
|
+
throw new PiboWebHttpError("Runtime binding repair is not available", 501);
|
|
4476
|
+
}
|
|
4477
|
+
const body = await readJsonBody(request);
|
|
4478
|
+
if (typeof body.runtimeInstanceId !== "string" || !body.runtimeInstanceId.trim()) {
|
|
4479
|
+
throw new PiboWebHttpError("runtimeInstanceId is required", 400);
|
|
4480
|
+
}
|
|
4481
|
+
if (!Number.isInteger(body.expectedRevision) || Number(body.expectedRevision) < 1) {
|
|
4482
|
+
throw new PiboWebHttpError("expectedRevision must be a positive integer", 400);
|
|
4483
|
+
}
|
|
4484
|
+
if (body.nativeSessionId !== undefined && typeof body.nativeSessionId !== "string") {
|
|
4485
|
+
throw new PiboWebHttpError("nativeSessionId must be a string", 400);
|
|
4486
|
+
}
|
|
4487
|
+
if (body.state !== undefined && body.state !== "unbound" && body.state !== "bound") {
|
|
4488
|
+
throw new PiboWebHttpError("state must be unbound or bound", 400);
|
|
4489
|
+
}
|
|
4490
|
+
const locator = body.locator;
|
|
4491
|
+
const locatorKinds = new Set(["local-file", "local-directory", "uri", "remote", "adapter-resolved"]);
|
|
4492
|
+
if (locator !== undefined
|
|
4493
|
+
&& (!isJsonObject(locator)
|
|
4494
|
+
|| typeof locator.kind !== "string"
|
|
4495
|
+
|| !locatorKinds.has(locator.kind)
|
|
4496
|
+
|| (locator.value !== undefined && typeof locator.value !== "string"))) {
|
|
4497
|
+
throw new PiboWebHttpError("locator must contain a supported kind and optional string value", 400);
|
|
4498
|
+
}
|
|
4499
|
+
try {
|
|
4500
|
+
const binding = await context.channelContext.rebindSessionRuntime(selectedSession.id, {
|
|
4501
|
+
runtimeInstanceId: body.runtimeInstanceId.trim(),
|
|
4502
|
+
nativeSessionId: typeof body.nativeSessionId === "string" && body.nativeSessionId.trim() ? body.nativeSessionId.trim() : undefined,
|
|
4503
|
+
state: body.state,
|
|
4504
|
+
locator: locator,
|
|
4505
|
+
expectedRevision: Number(body.expectedRevision),
|
|
4506
|
+
});
|
|
4507
|
+
const updated = context.channelContext.getSession(selectedSession.id);
|
|
4508
|
+
if (updated)
|
|
4509
|
+
state.sessionQuery.upsertSession(updated);
|
|
4510
|
+
return responseJson({ binding });
|
|
4511
|
+
}
|
|
4512
|
+
catch (error) {
|
|
4513
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4514
|
+
const status = /concurrently|idle/i.test(message) ? 409 : 400;
|
|
4515
|
+
throw new PiboWebHttpError(message, status);
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4199
4518
|
const patchSessionId = sessionResourceId(url.pathname);
|
|
4200
4519
|
if (patchSessionId && request.method === "PATCH") {
|
|
4201
4520
|
requireSameOriginJsonRequest(request);
|
|
@@ -4241,7 +4560,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4241
4560
|
if (confirmText !== "Delete this session") {
|
|
4242
4561
|
throw new PiboWebHttpError('Type "Delete this session" to permanently delete this session.', 400);
|
|
4243
4562
|
}
|
|
4244
|
-
const deletedSessionIds = deleteSessionSubtree(state, context, webSession, selectedSession);
|
|
4563
|
+
const deletedSessionIds = await deleteSessionSubtree(state, context, webSession, selectedSession);
|
|
4245
4564
|
return responseJson({ deletedSessionIds });
|
|
4246
4565
|
}
|
|
4247
4566
|
if ((sessionAction?.action === "kill" || sessionAction?.action === "kill-all") && request.method === "POST") {
|
|
@@ -4262,27 +4581,30 @@ export function createChatWebApp(options = {}) {
|
|
|
4262
4581
|
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, url.searchParams.get("piboSessionId") || undefined);
|
|
4263
4582
|
state.sessionQuery.upsertSession(selectedSession);
|
|
4264
4583
|
const indexedSession = state.sessionQuery.getSession(selectedSession.id);
|
|
4265
|
-
const
|
|
4266
|
-
const
|
|
4267
|
-
const
|
|
4584
|
+
const historyStartedAt = performance.now();
|
|
4585
|
+
const productHistory = state.historyQuery.getProductHistoryCoverage(selectedSession.id);
|
|
4586
|
+
const historyInspection = requiresNativeHistoryCompatibility(selectedSession) && context.channelContext.inspectSessionRuntimeHistory
|
|
4587
|
+
? await context.channelContext.inspectSessionRuntimeHistory(selectedSession.id).catch(() => undefined)
|
|
4588
|
+
: undefined;
|
|
4589
|
+
const historyMs = performance.now() - historyStartedAt;
|
|
4268
4590
|
const lastEventSequence = state.timelineQuery.getLatestEventSequence(selectedSession.id);
|
|
4269
4591
|
const latestStreamId = state.timelineQuery.getLatestStreamId({ piboSessionId: selectedSession.id });
|
|
4270
|
-
const version =
|
|
4592
|
+
const version = createFastTraceV2Version({
|
|
4271
4593
|
session: selectedSession,
|
|
4272
4594
|
sessions: listSharedSessions(context),
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
: [],
|
|
4595
|
+
lastEventSequence,
|
|
4596
|
+
lastActivityAt: indexedSession?.lastActivityAt,
|
|
4276
4597
|
status: indexedSession?.status,
|
|
4277
|
-
metadata,
|
|
4278
4598
|
latestStreamId,
|
|
4599
|
+
productHistory,
|
|
4600
|
+
nativeHistoryVersion: historyInspection?.version,
|
|
4279
4601
|
});
|
|
4280
4602
|
const headers = {
|
|
4281
4603
|
etag: etagForVersion(version),
|
|
4282
4604
|
"x-pibo-trace-version": version,
|
|
4283
4605
|
"server-timing": [
|
|
4284
4606
|
`trace_summary;dur=${(performance.now() - startedAt).toFixed(1)}`,
|
|
4285
|
-
`
|
|
4607
|
+
`trace_history;dur=${historyMs.toFixed(1)}`,
|
|
4286
4608
|
`trace_events;desc="${lastEventSequence}"`,
|
|
4287
4609
|
].join(", "),
|
|
4288
4610
|
};
|
|
@@ -4292,7 +4614,8 @@ export function createChatWebApp(options = {}) {
|
|
|
4292
4614
|
const summary = {
|
|
4293
4615
|
piboSessionId: selectedSession.id,
|
|
4294
4616
|
piSessionId: selectedSession.piSessionId,
|
|
4295
|
-
|
|
4617
|
+
runtimeBinding: traceRuntimeBindingFromSession(selectedSession),
|
|
4618
|
+
title: selectedSession.title ?? historyInspection?.title ?? historyInspection?.firstMessage ?? "Untitled Session",
|
|
4296
4619
|
version,
|
|
4297
4620
|
latestStreamId,
|
|
4298
4621
|
eventCount: lastEventSequence,
|
|
@@ -4307,10 +4630,13 @@ export function createChatWebApp(options = {}) {
|
|
|
4307
4630
|
const beforeSequence = timelineCursor.kind === "event" ? timelineCursor.beforeSequence : undefined;
|
|
4308
4631
|
const limit = parsePositiveIntSearchParam(url, "limit", TRACE_V2_DEFAULT_TIMELINE_LIMIT, TRACE_V2_MAX_TIMELINE_LIMIT);
|
|
4309
4632
|
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, url.searchParams.get("piboSessionId") || undefined);
|
|
4633
|
+
if (timelineCursor.kind === "history")
|
|
4634
|
+
validateRuntimeHistoryCursor(selectedSession, timelineCursor);
|
|
4310
4635
|
state.sessionQuery.upsertSession(selectedSession);
|
|
4311
4636
|
const ownedSessions = listSharedSessions(context);
|
|
4312
4637
|
const indexedSession = state.sessionQuery.getSession(selectedSession.id);
|
|
4313
|
-
let
|
|
4638
|
+
let historyMs = 0;
|
|
4639
|
+
const productHistory = state.historyQuery.getProductHistoryCoverage(selectedSession.id);
|
|
4314
4640
|
const lastEventSequence = state.timelineQuery.getLatestEventSequence(selectedSession.id);
|
|
4315
4641
|
const latestStreamId = state.timelineQuery.getLatestStreamId({ piboSessionId: selectedSession.id });
|
|
4316
4642
|
const turnTimings = state.timelineQuery.listMessageTurnTimings(selectedSession.id);
|
|
@@ -4319,11 +4645,12 @@ export function createChatWebApp(options = {}) {
|
|
|
4319
4645
|
? context.channelContext.getSessionRuntimeStatus(selectedSession.id) ?? null
|
|
4320
4646
|
: undefined;
|
|
4321
4647
|
const traceStatus = traceProjectionStatus(liveSnapshots, indexedSession?.status, turnTimings, runtimeStatus);
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4648
|
+
let historyInspection;
|
|
4649
|
+
if (timelineCursor.kind === "tail" && requiresNativeHistoryCompatibility(selectedSession) && context.channelContext.inspectSessionRuntimeHistory) {
|
|
4650
|
+
const historyStartedAt = performance.now();
|
|
4651
|
+
historyInspection = await context.channelContext.inspectSessionRuntimeHistory(selectedSession.id).catch(() => undefined);
|
|
4652
|
+
historyMs += performance.now() - historyStartedAt;
|
|
4653
|
+
}
|
|
4327
4654
|
const baseVersion = createFastTraceV2Version({
|
|
4328
4655
|
session: selectedSession,
|
|
4329
4656
|
sessions: ownedSessions,
|
|
@@ -4331,7 +4658,8 @@ export function createChatWebApp(options = {}) {
|
|
|
4331
4658
|
lastActivityAt: indexedSession?.lastActivityAt,
|
|
4332
4659
|
status: traceStatus,
|
|
4333
4660
|
latestStreamId,
|
|
4334
|
-
|
|
4661
|
+
productHistory,
|
|
4662
|
+
nativeHistoryVersion: historyInspection?.version,
|
|
4335
4663
|
});
|
|
4336
4664
|
const snapshotVersion = liveSnapshotVersion(liveSnapshots);
|
|
4337
4665
|
const version = snapshotVersion ? `${baseVersion}:live:${snapshotVersion}` : baseVersion;
|
|
@@ -4354,7 +4682,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4354
4682
|
...baseHeaders,
|
|
4355
4683
|
"server-timing": [
|
|
4356
4684
|
`trace_timeline;dur=${(performance.now() - startedAt).toFixed(1)}`,
|
|
4357
|
-
`
|
|
4685
|
+
`trace_history;dur=${historyMs.toFixed(1)}`,
|
|
4358
4686
|
`trace_events;desc="0"`,
|
|
4359
4687
|
`trace_cache;desc="page-hit"`,
|
|
4360
4688
|
].join(", "),
|
|
@@ -4364,22 +4692,32 @@ export function createChatWebApp(options = {}) {
|
|
|
4364
4692
|
let trace = cached;
|
|
4365
4693
|
let eventCount = 0;
|
|
4366
4694
|
if (!trace) {
|
|
4367
|
-
if (timelineCursor.kind === "
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4695
|
+
if (timelineCursor.kind === "history") {
|
|
4696
|
+
if (!context.channelContext.readSessionRuntimeHistory) {
|
|
4697
|
+
throw new PiboWebHttpError("Runtime history is unavailable for this gateway", 501);
|
|
4698
|
+
}
|
|
4699
|
+
const historyStartedAt = performance.now();
|
|
4700
|
+
let history;
|
|
4701
|
+
try {
|
|
4702
|
+
history = await context.channelContext.readSessionRuntimeHistory(selectedSession.id, {
|
|
4703
|
+
cursor: timelineCursor.providerCursor,
|
|
4371
4704
|
beforeTimestamp: timelineCursor.beforeTimestamp,
|
|
4372
4705
|
limit,
|
|
4373
|
-
})
|
|
4374
|
-
|
|
4706
|
+
});
|
|
4707
|
+
}
|
|
4708
|
+
catch {
|
|
4709
|
+
throw new PiboWebHttpError("Runtime history could not be read for this page", 502);
|
|
4710
|
+
}
|
|
4711
|
+
historyMs += performance.now() - historyStartedAt;
|
|
4712
|
+
historyInspection = history.inspection;
|
|
4375
4713
|
trace = await buildTraceView({
|
|
4376
4714
|
session: selectedSession,
|
|
4377
4715
|
sessions: ownedSessions,
|
|
4378
4716
|
events: [],
|
|
4379
4717
|
status: traceStatus,
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4718
|
+
historyEntries: history.entries,
|
|
4719
|
+
historyInspection: history.inspection,
|
|
4720
|
+
historyOrderOffset: history.orderOffset,
|
|
4383
4721
|
turnTimings,
|
|
4384
4722
|
includeRawEvents: false,
|
|
4385
4723
|
latestStreamId,
|
|
@@ -4390,10 +4728,13 @@ export function createChatWebApp(options = {}) {
|
|
|
4390
4728
|
eventLimit: limit,
|
|
4391
4729
|
pageSize: limit,
|
|
4392
4730
|
beforeCursor: timelineCursor.raw,
|
|
4393
|
-
nextBeforeCursor: history.
|
|
4394
|
-
?
|
|
4731
|
+
nextBeforeCursor: history.hasMore
|
|
4732
|
+
? encodeRuntimeHistoryTimelineCursor(selectedSession, {
|
|
4733
|
+
providerCursor: history.nextCursor,
|
|
4734
|
+
beforeTimestamp: timelineCursor.beforeTimestamp,
|
|
4735
|
+
})
|
|
4395
4736
|
: undefined,
|
|
4396
|
-
hasOlderEvents: history.
|
|
4737
|
+
hasOlderEvents: history.hasMore,
|
|
4397
4738
|
};
|
|
4398
4739
|
}
|
|
4399
4740
|
else {
|
|
@@ -4402,17 +4743,32 @@ export function createChatWebApp(options = {}) {
|
|
|
4402
4743
|
limit,
|
|
4403
4744
|
...(beforeSequence !== undefined ? { beforeSequence } : {}),
|
|
4404
4745
|
});
|
|
4405
|
-
const transcriptEntries = timelineCursor.kind === "tail" && transcriptMetadata?.sessionPath
|
|
4406
|
-
? readTailEntries(transcriptMetadata.sessionPath)
|
|
4407
|
-
: [];
|
|
4408
4746
|
eventCount = events.length;
|
|
4747
|
+
let nativeHistory;
|
|
4748
|
+
if (timelineCursor.kind === "tail"
|
|
4749
|
+
&& requiresNativeHistoryCompatibility(selectedSession)
|
|
4750
|
+
&& runtimeHistorySupported(context, selectedSession)
|
|
4751
|
+
&& context.channelContext.readSessionRuntimeHistory) {
|
|
4752
|
+
const historyStartedAt = performance.now();
|
|
4753
|
+
nativeHistory = await context.channelContext.readSessionRuntimeHistory(selectedSession.id, { limit: Math.min(limit * 4, 500) }).catch(() => undefined);
|
|
4754
|
+
historyMs += performance.now() - historyStartedAt;
|
|
4755
|
+
historyInspection = nativeHistory?.inspection ?? historyInspection;
|
|
4756
|
+
}
|
|
4757
|
+
const historyEntries = nativeHistory?.entries.length
|
|
4758
|
+
? nativeHistory.entries
|
|
4759
|
+
: state.historyQuery.listProductHistoryEntries({
|
|
4760
|
+
piboSessionId: selectedSession.id,
|
|
4761
|
+
limit: Math.min(limit * 2, 500),
|
|
4762
|
+
...(beforeSequence !== undefined ? { beforeSequence } : {}),
|
|
4763
|
+
});
|
|
4409
4764
|
trace = await buildTraceView({
|
|
4410
4765
|
session: selectedSession,
|
|
4411
4766
|
sessions: ownedSessions,
|
|
4412
4767
|
events,
|
|
4413
4768
|
status: traceStatus,
|
|
4414
|
-
|
|
4415
|
-
|
|
4769
|
+
historyEntries,
|
|
4770
|
+
historyInspection,
|
|
4771
|
+
historyOrderOffset: nativeHistory?.orderOffset,
|
|
4416
4772
|
turnTimings,
|
|
4417
4773
|
includeRawEvents: false,
|
|
4418
4774
|
latestStreamId,
|
|
@@ -4423,19 +4779,24 @@ export function createChatWebApp(options = {}) {
|
|
|
4423
4779
|
beforeSequence,
|
|
4424
4780
|
beforeCursor: timelineCursor.kind === "event" ? timelineCursor.raw : undefined,
|
|
4425
4781
|
});
|
|
4426
|
-
if (trace.hasOlderEvents !== true &&
|
|
4427
|
-
|
|
4782
|
+
if (trace.hasOlderEvents !== true && nativeHistory?.hasMore) {
|
|
4783
|
+
trace = {
|
|
4784
|
+
...trace,
|
|
4785
|
+
nextBeforeCursor: encodeRuntimeHistoryTimelineCursor(selectedSession, {
|
|
4786
|
+
providerCursor: nativeHistory.nextCursor,
|
|
4787
|
+
}),
|
|
4788
|
+
hasOlderEvents: true,
|
|
4789
|
+
};
|
|
4790
|
+
}
|
|
4791
|
+
else if (trace.hasOlderEvents !== true && events.length > 0 && runtimeHistorySupported(context, selectedSession)) {
|
|
4792
|
+
const cutoff = compactionCutoffTimestamp(events)
|
|
4793
|
+
?? (requiresNativeHistoryCompatibility(selectedSession) ? events[0]?.createdAt : undefined);
|
|
4428
4794
|
if (cutoff) {
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
...trace,
|
|
4435
|
-
nextBeforeCursor: encodeTranscriptTimelineCursor(metadata.sessionSize, cutoff),
|
|
4436
|
-
hasOlderEvents: true,
|
|
4437
|
-
};
|
|
4438
|
-
}
|
|
4795
|
+
trace = {
|
|
4796
|
+
...trace,
|
|
4797
|
+
nextBeforeCursor: encodeRuntimeHistoryTimelineCursor(selectedSession, { beforeTimestamp: cutoff }),
|
|
4798
|
+
hasOlderEvents: true,
|
|
4799
|
+
};
|
|
4439
4800
|
}
|
|
4440
4801
|
}
|
|
4441
4802
|
}
|
|
@@ -4447,21 +4808,12 @@ export function createChatWebApp(options = {}) {
|
|
|
4447
4808
|
status: traceStatus,
|
|
4448
4809
|
});
|
|
4449
4810
|
trace = { ...trace, version };
|
|
4450
|
-
const transcriptTailCursor = timelineCursor.kind === "tail"
|
|
4451
|
-
? originTranscriptTailCursor({
|
|
4452
|
-
session: selectedSession,
|
|
4453
|
-
trace,
|
|
4454
|
-
metadata: transcriptMetadata,
|
|
4455
|
-
limit,
|
|
4456
|
-
})
|
|
4457
|
-
: undefined;
|
|
4458
4811
|
const page = traceTimelinePageFromView({
|
|
4459
4812
|
trace,
|
|
4460
4813
|
payloadStore: state.dataStore.payloads,
|
|
4461
4814
|
limit,
|
|
4462
4815
|
byteLimit: TRACE_V2_TIMELINE_HARD_BYTES,
|
|
4463
4816
|
fromTail: timelineCursor.kind === "tail",
|
|
4464
|
-
transcriptTailCursor,
|
|
4465
4817
|
});
|
|
4466
4818
|
setTraceTimelinePageCache(state.traceTimelinePageCache, pageCacheKey, page);
|
|
4467
4819
|
return responseJson(page, {
|
|
@@ -4469,7 +4821,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4469
4821
|
...baseHeaders,
|
|
4470
4822
|
"server-timing": [
|
|
4471
4823
|
`trace_timeline;dur=${(performance.now() - startedAt).toFixed(1)}`,
|
|
4472
|
-
`
|
|
4824
|
+
`trace_history;dur=${historyMs.toFixed(1)}`,
|
|
4473
4825
|
`trace_events;desc="${eventCount}"`,
|
|
4474
4826
|
`trace_cache;desc="${cached ? "hit" : "miss"}"`,
|
|
4475
4827
|
].join(", "),
|
|
@@ -4493,7 +4845,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4493
4845
|
if (url.pathname === `${CHAT_WEB_API_PREFIX}/trace/raw-events` && request.method === "GET") {
|
|
4494
4846
|
const webSession = await requireSession(request, context);
|
|
4495
4847
|
const rawCursor = parseTimelineBeforeCursor(url);
|
|
4496
|
-
if (rawCursor.kind === "
|
|
4848
|
+
if (rawCursor.kind === "history")
|
|
4497
4849
|
throw new PiboWebHttpError("Raw event cursor must be tail or a positive sequence", 400);
|
|
4498
4850
|
const beforeSequence = rawCursor.kind === "event" ? rawCursor.beforeSequence : undefined;
|
|
4499
4851
|
const limit = parsePositiveIntSearchParam(url, "limit", TRACE_V2_RAW_EVENTS_DEFAULT_LIMIT, TRACE_V2_RAW_EVENTS_MAX_LIMIT);
|
|
@@ -4523,9 +4875,17 @@ export function createChatWebApp(options = {}) {
|
|
|
4523
4875
|
state.sessionQuery.upsertSession(selectedSession);
|
|
4524
4876
|
const ownedSessions = listSharedSessions(context);
|
|
4525
4877
|
const indexedSession = state.sessionQuery.getSession(selectedSession.id);
|
|
4526
|
-
|
|
4527
|
-
const
|
|
4528
|
-
|
|
4878
|
+
let historyMs = 0;
|
|
4879
|
+
const productHistory = state.historyQuery.getProductHistoryCoverage(selectedSession.id);
|
|
4880
|
+
let nativeHistory;
|
|
4881
|
+
if (beforeSequence === undefined
|
|
4882
|
+
&& requiresNativeHistoryCompatibility(selectedSession)
|
|
4883
|
+
&& runtimeHistorySupported(context, selectedSession)
|
|
4884
|
+
&& context.channelContext.readSessionRuntimeHistory) {
|
|
4885
|
+
const historyStartedAt = performance.now();
|
|
4886
|
+
nativeHistory = await context.channelContext.readSessionRuntimeHistory(selectedSession.id, { limit: Math.min(eventLimit * 4, 500) }).catch(() => undefined);
|
|
4887
|
+
historyMs += performance.now() - historyStartedAt;
|
|
4888
|
+
}
|
|
4529
4889
|
const lastEventSequence = state.timelineQuery.getLatestEventSequence(selectedSession.id);
|
|
4530
4890
|
const latestStreamId = state.timelineQuery.getLatestStreamId({ piboSessionId: selectedSession.id });
|
|
4531
4891
|
const turnTimings = state.timelineQuery.listMessageTurnTimings(selectedSession.id);
|
|
@@ -4534,15 +4894,15 @@ export function createChatWebApp(options = {}) {
|
|
|
4534
4894
|
? context.channelContext.getSessionRuntimeStatus(selectedSession.id) ?? null
|
|
4535
4895
|
: undefined;
|
|
4536
4896
|
const traceStatus = traceProjectionStatus(liveSnapshots, indexedSession?.status, turnTimings, runtimeStatus);
|
|
4537
|
-
const baseVersion =
|
|
4897
|
+
const baseVersion = createFastTraceV2Version({
|
|
4538
4898
|
session: selectedSession,
|
|
4539
4899
|
sessions: ownedSessions,
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
: [],
|
|
4900
|
+
lastEventSequence,
|
|
4901
|
+
lastActivityAt: indexedSession?.lastActivityAt,
|
|
4543
4902
|
status: traceStatus,
|
|
4544
|
-
metadata,
|
|
4545
4903
|
latestStreamId,
|
|
4904
|
+
productHistory,
|
|
4905
|
+
nativeHistoryVersion: nativeHistory?.inspection?.version,
|
|
4546
4906
|
});
|
|
4547
4907
|
const snapshotVersion = liveSnapshotVersion(liveSnapshots);
|
|
4548
4908
|
const version = snapshotVersion ? `${baseVersion}:live:${snapshotVersion}` : baseVersion;
|
|
@@ -4552,7 +4912,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4552
4912
|
const serverTiming = (cacheState, eventCount = 0) => ({
|
|
4553
4913
|
"server-timing": [
|
|
4554
4914
|
`trace;dur=${(performance.now() - startedAt).toFixed(1)}`,
|
|
4555
|
-
`
|
|
4915
|
+
`trace_history;dur=${historyMs.toFixed(1)}`,
|
|
4556
4916
|
`trace_events;desc="${eventCount}"`,
|
|
4557
4917
|
`trace_cache;desc="${cacheState}"`,
|
|
4558
4918
|
].join(", "),
|
|
@@ -4570,12 +4930,21 @@ export function createChatWebApp(options = {}) {
|
|
|
4570
4930
|
...(beforeSequence !== undefined ? { beforeSequence } : {}),
|
|
4571
4931
|
});
|
|
4572
4932
|
eventCount = events.length;
|
|
4933
|
+
const historyEntries = nativeHistory?.entries.length
|
|
4934
|
+
? nativeHistory.entries
|
|
4935
|
+
: state.historyQuery.listProductHistoryEntries({
|
|
4936
|
+
piboSessionId: selectedSession.id,
|
|
4937
|
+
limit: Math.min(eventLimit * 2, 1000),
|
|
4938
|
+
...(beforeSequence !== undefined ? { beforeSequence } : {}),
|
|
4939
|
+
});
|
|
4573
4940
|
trace = await buildTraceView({
|
|
4574
4941
|
session: selectedSession,
|
|
4575
4942
|
sessions: ownedSessions,
|
|
4576
4943
|
events,
|
|
4577
4944
|
status: traceStatus,
|
|
4578
|
-
|
|
4945
|
+
historyEntries,
|
|
4946
|
+
historyInspection: nativeHistory?.inspection,
|
|
4947
|
+
historyOrderOffset: nativeHistory?.orderOffset,
|
|
4579
4948
|
turnTimings,
|
|
4580
4949
|
includeRawEvents: false,
|
|
4581
4950
|
latestStreamId,
|
|
@@ -4637,6 +5006,11 @@ export function createChatWebApp(options = {}) {
|
|
|
4637
5006
|
session,
|
|
4638
5007
|
sessions: ownedSessions,
|
|
4639
5008
|
events: state.timelineQuery.listTraceEvents({ piboSessionId, beforeOrAtSequence: eventSequence, limit: DEFAULT_TRACE_EVENTS_PAGE_SIZE }),
|
|
5009
|
+
historyEntries: state.historyQuery.listProductHistoryEntries({
|
|
5010
|
+
piboSessionId,
|
|
5011
|
+
limit: DEFAULT_TRACE_EVENTS_PAGE_SIZE,
|
|
5012
|
+
beforeSequence: eventSequence + 1,
|
|
5013
|
+
}),
|
|
4640
5014
|
status: indexedSession?.status,
|
|
4641
5015
|
turnTimings: state.timelineQuery.listMessageTurnTimings(piboSessionId),
|
|
4642
5016
|
});
|
|
@@ -4654,6 +5028,34 @@ export function createChatWebApp(options = {}) {
|
|
|
4654
5028
|
const body = await readJsonBody(request);
|
|
4655
5029
|
return sendChatMessage({ state, context, webSession, defaultProfile, body });
|
|
4656
5030
|
}
|
|
5031
|
+
if (url.pathname === `${CHAT_WEB_API_PREFIX}/provider-auth` && request.method === "GET") {
|
|
5032
|
+
await requireSession(request, context);
|
|
5033
|
+
return responseJson(await readProviderAuthCatalog(context.channelContext, defaultRuntimeInstanceId(context, defaultProfile)), { headers: { "cache-control": "no-store" } });
|
|
5034
|
+
}
|
|
5035
|
+
if (url.pathname === `${CHAT_WEB_API_PREFIX}/provider-auth` && request.method === "POST") {
|
|
5036
|
+
requireSameOriginJsonRequest(request);
|
|
5037
|
+
await requireSession(request, context);
|
|
5038
|
+
const body = await readJsonBody(request);
|
|
5039
|
+
const action = typeof body.action === "string" ? body.action : "";
|
|
5040
|
+
const mappedAction = action === "start"
|
|
5041
|
+
? "login.start"
|
|
5042
|
+
: action === "complete"
|
|
5043
|
+
? "login.complete"
|
|
5044
|
+
: action === "api_key"
|
|
5045
|
+
? "login.apikey"
|
|
5046
|
+
: action === "cancel"
|
|
5047
|
+
? "login.cancel"
|
|
5048
|
+
: action === "logout"
|
|
5049
|
+
? "logout"
|
|
5050
|
+
: isProviderAuthAction(action) && action !== "login.status"
|
|
5051
|
+
? action
|
|
5052
|
+
: undefined;
|
|
5053
|
+
if (!mappedAction)
|
|
5054
|
+
throw new PiboWebHttpError("Unsupported provider authentication action", 400);
|
|
5055
|
+
const result = await executeProviderAuthAction(context.channelContext, mappedAction, body);
|
|
5056
|
+
invalidateBootstrapCatalogCache(state);
|
|
5057
|
+
return responseJson({ result }, { headers: { "cache-control": "no-store" } });
|
|
5058
|
+
}
|
|
4657
5059
|
if (url.pathname === `${CHAT_WEB_API_PREFIX}/status` && request.method === "GET") {
|
|
4658
5060
|
const webSession = await requireSession(request, context);
|
|
4659
5061
|
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, url.searchParams.get("piboSessionId") || undefined);
|
|
@@ -4677,7 +5079,30 @@ export function createChatWebApp(options = {}) {
|
|
|
4677
5079
|
}
|
|
4678
5080
|
const piboSessionId = typeof body.piboSessionId === "string" ? body.piboSessionId : undefined;
|
|
4679
5081
|
if (isProviderAuthAction(body.action)) {
|
|
4680
|
-
|
|
5082
|
+
const authParams = isJsonObject(body.params) ? { ...body.params } : {};
|
|
5083
|
+
const explicitRuntimeInstanceId = typeof authParams.runtimeInstanceId === "string" && authParams.runtimeInstanceId.trim()
|
|
5084
|
+
? authParams.runtimeInstanceId.trim()
|
|
5085
|
+
: undefined;
|
|
5086
|
+
const selectedSession = piboSessionId
|
|
5087
|
+
? resolveRequestedSession(state, context, webSession, defaultProfile, piboSessionId)
|
|
5088
|
+
: undefined;
|
|
5089
|
+
const boundRuntimeInstanceId = selectedSession ? sessionRuntimeInstanceId(context, selectedSession) : undefined;
|
|
5090
|
+
if (explicitRuntimeInstanceId && boundRuntimeInstanceId && explicitRuntimeInstanceId !== boundRuntimeInstanceId) {
|
|
5091
|
+
throw new PiboWebHttpError("Provider authentication target conflicts with the selected session runtime", 409);
|
|
5092
|
+
}
|
|
5093
|
+
const selectedRuntimeInstanceId = explicitRuntimeInstanceId ?? boundRuntimeInstanceId;
|
|
5094
|
+
if (!selectedRuntimeInstanceId) {
|
|
5095
|
+
throw new PiboWebHttpError("Provider authentication requires an explicit runtimeInstanceId or a valid bound Pibo Session", 400);
|
|
5096
|
+
}
|
|
5097
|
+
authParams.runtimeInstanceId = selectedRuntimeInstanceId;
|
|
5098
|
+
const result = await executeProviderAuthAction(context.channelContext, body.action, authParams);
|
|
5099
|
+
if (body.action !== "login.status")
|
|
5100
|
+
invalidateBootstrapCatalogCache(state);
|
|
5101
|
+
return providerAuthActionResponse({
|
|
5102
|
+
piboSessionId: selectedSession?.id,
|
|
5103
|
+
action: body.action,
|
|
5104
|
+
result,
|
|
5105
|
+
});
|
|
4681
5106
|
}
|
|
4682
5107
|
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, piboSessionId);
|
|
4683
5108
|
const room = ensureSessionRoom(state, context, selectedSession, webSession);
|