@pasko70/pibo 3.3.0 → 3.4.1
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/capabilities.js +5 -0
- package/dist/agent-runtime/contract.js +2 -0
- package/dist/agent-runtime/routed-session.js +70 -11
- package/dist/agent-runtimes/codex-native/adapter.js +3 -0
- package/dist/agent-runtimes/codex-native/thread.js +26 -4
- package/dist/agent-runtimes/omp/adapter.js +1 -0
- package/dist/agent-runtimes/pi/adapter.js +4 -0
- package/dist/agent-runtimes/pi/routed-session.js +53 -5
- package/dist/apps/chat/chat-api-routes.js +11 -37
- package/dist/apps/chat/chat-request-normalizers.js +8 -48
- package/dist/apps/chat/data/legacy-project-migration.js +492 -0
- package/dist/apps/chat/data/room-service.js +2 -2
- package/dist/apps/chat/data/workflow-session-model.js +1 -0
- package/dist/apps/chat/data/workflow-session-service.js +352 -0
- package/dist/apps/chat/rooms.js +1 -1
- package/dist/apps/chat/types/rooms.js +30 -0
- package/dist/apps/chat/web-app.js +264 -647
- package/dist/apps/chat/workflow-catalog.js +18 -18
- package/dist/apps/chat/{project-workflow-human-actions.js → workflow-human-actions.js} +14 -14
- package/dist/apps/chat/workflow-manual-trigger-runtime.js +5 -1
- package/dist/apps/chat/workflow-persistence.js +20 -28
- package/dist/apps/chat/{project-workflow-sessions.js → workflow-sessions.js} +18 -17
- package/dist/apps/chat-ui/assets/{dist-Kc3zbvQi.js → dist-Abz605MV.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C9a0_446.js → dist-D0md0xIR.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CcAkJ8iv.js → dist-DHnaUMlq.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Bd9gWCbk.js → dist-DnZL1rRp.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BbCjOLiw.js → dist-ERKABhp3.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BWVPNFjU.js +228 -0
- package/dist/apps/chat-ui/assets/index-CywOD6EF.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-CZmxeSn3.js +43 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/compute/pool/cli.js +1 -1
- package/dist/compute/pool/seeds.js +2 -3
- package/dist/config/config.js +1 -1
- package/dist/core/session-router.js +13 -4
- package/dist/previews/cli.js +154 -79
- package/dist/previews/compute-worker.js +37 -0
- package/dist/previews/config.js +2 -1
- package/dist/previews/migrations/session-ownership.js +7 -0
- package/dist/previews/proxy.js +4 -2
- package/dist/previews/public-setup.js +108 -0
- package/dist/previews/store.js +20 -13
- package/dist/previews/web-app.js +97 -2
- package/dist/sessions/workflow-session-kind.js +0 -3
- package/npm-shrinkwrap.json +7 -6
- package/package.json +6 -2
- package/packages/workflows/README.md +21 -0
- package/packages/workflows/dist/api/index.d.ts +48 -0
- package/packages/workflows/dist/api/index.d.ts.map +1 -0
- package/packages/workflows/dist/api/index.js +96 -0
- package/packages/workflows/dist/api/index.js.map +1 -0
- package/packages/workflows/dist/definition-hash.d.ts +4 -0
- package/packages/workflows/dist/definition-hash.d.ts.map +1 -0
- package/packages/workflows/dist/definition-hash.js +27 -0
- package/packages/workflows/dist/definition-hash.js.map +1 -0
- package/packages/workflows/dist/fixtures/index.d.ts +39 -0
- package/packages/workflows/dist/fixtures/index.d.ts.map +1 -0
- package/packages/workflows/dist/fixtures/index.js +608 -0
- package/packages/workflows/dist/fixtures/index.js.map +1 -0
- package/packages/workflows/dist/index.d.ts +16 -0
- package/packages/workflows/dist/index.d.ts.map +1 -0
- package/packages/workflows/dist/index.js +10 -0
- package/packages/workflows/dist/index.js.map +1 -0
- package/packages/workflows/dist/inspection/index.d.ts +47 -0
- package/packages/workflows/dist/inspection/index.d.ts.map +1 -0
- package/packages/workflows/dist/inspection/index.js +131 -0
- package/packages/workflows/dist/inspection/index.js.map +1 -0
- package/packages/workflows/dist/registry/index.d.ts +30 -0
- package/packages/workflows/dist/registry/index.d.ts.map +1 -0
- package/packages/workflows/dist/registry/index.js +161 -0
- package/packages/workflows/dist/registry/index.js.map +1 -0
- package/packages/workflows/dist/runtime/adapter-node.d.ts +28 -0
- package/packages/workflows/dist/runtime/adapter-node.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/adapter-node.js +172 -0
- package/packages/workflows/dist/runtime/adapter-node.js.map +1 -0
- package/packages/workflows/dist/runtime/agent-node.d.ts +32 -0
- package/packages/workflows/dist/runtime/agent-node.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/agent-node.js +231 -0
- package/packages/workflows/dist/runtime/agent-node.js.map +1 -0
- package/packages/workflows/dist/runtime/agent-runtime.d.ts +25 -0
- package/packages/workflows/dist/runtime/agent-runtime.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/agent-runtime.js +111 -0
- package/packages/workflows/dist/runtime/agent-runtime.js.map +1 -0
- package/packages/workflows/dist/runtime/code-node.d.ts +31 -0
- package/packages/workflows/dist/runtime/code-node.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/code-node.js +223 -0
- package/packages/workflows/dist/runtime/code-node.js.map +1 -0
- package/packages/workflows/dist/runtime/dispatch-failures.d.ts +36 -0
- package/packages/workflows/dist/runtime/dispatch-failures.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/dispatch-failures.js +80 -0
- package/packages/workflows/dist/runtime/dispatch-failures.js.map +1 -0
- package/packages/workflows/dist/runtime/edge-payloads.d.ts +3 -0
- package/packages/workflows/dist/runtime/edge-payloads.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/edge-payloads.js +11 -0
- package/packages/workflows/dist/runtime/edge-payloads.js.map +1 -0
- package/packages/workflows/dist/runtime/edge-transfer.d.ts +39 -0
- package/packages/workflows/dist/runtime/edge-transfer.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/edge-transfer.js +356 -0
- package/packages/workflows/dist/runtime/edge-transfer.js.map +1 -0
- package/packages/workflows/dist/runtime/human-action.d.ts +43 -0
- package/packages/workflows/dist/runtime/human-action.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/human-action.js +231 -0
- package/packages/workflows/dist/runtime/human-action.js.map +1 -0
- package/packages/workflows/dist/runtime/human-node.d.ts +27 -0
- package/packages/workflows/dist/runtime/human-node.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/human-node.js +126 -0
- package/packages/workflows/dist/runtime/human-node.js.map +1 -0
- package/packages/workflows/dist/runtime/ids.d.ts +2 -0
- package/packages/workflows/dist/runtime/ids.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/ids.js +4 -0
- package/packages/workflows/dist/runtime/ids.js.map +1 -0
- package/packages/workflows/dist/runtime/index.d.ts +23 -0
- package/packages/workflows/dist/runtime/index.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/index.js +12 -0
- package/packages/workflows/dist/runtime/index.js.map +1 -0
- package/packages/workflows/dist/runtime/manual-trigger.d.ts +51 -0
- package/packages/workflows/dist/runtime/manual-trigger.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/manual-trigger.js +403 -0
- package/packages/workflows/dist/runtime/manual-trigger.js.map +1 -0
- package/packages/workflows/dist/runtime/nested-workflow-node.d.ts +48 -0
- package/packages/workflows/dist/runtime/nested-workflow-node.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/nested-workflow-node.js +246 -0
- package/packages/workflows/dist/runtime/nested-workflow-node.js.map +1 -0
- package/packages/workflows/dist/runtime/one-node-agent.d.ts +34 -0
- package/packages/workflows/dist/runtime/one-node-agent.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/one-node-agent.js +334 -0
- package/packages/workflows/dist/runtime/one-node-agent.js.map +1 -0
- package/packages/workflows/dist/runtime/persistence.d.ts +9 -0
- package/packages/workflows/dist/runtime/persistence.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/persistence.js +67 -0
- package/packages/workflows/dist/runtime/persistence.js.map +1 -0
- package/packages/workflows/dist/runtime/pibo-routing.d.ts +126 -0
- package/packages/workflows/dist/runtime/pibo-routing.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/pibo-routing.js +96 -0
- package/packages/workflows/dist/runtime/pibo-routing.js.map +1 -0
- package/packages/workflows/dist/runtime/prompts.d.ts +20 -0
- package/packages/workflows/dist/runtime/prompts.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/prompts.js +235 -0
- package/packages/workflows/dist/runtime/prompts.js.map +1 -0
- package/packages/workflows/dist/runtime/retry.d.ts +35 -0
- package/packages/workflows/dist/runtime/retry.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/retry.js +80 -0
- package/packages/workflows/dist/runtime/retry.js.map +1 -0
- package/packages/workflows/dist/runtime/state.d.ts +14 -0
- package/packages/workflows/dist/runtime/state.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/state.js +139 -0
- package/packages/workflows/dist/runtime/state.js.map +1 -0
- package/packages/workflows/dist/runtime/time.d.ts +6 -0
- package/packages/workflows/dist/runtime/time.d.ts.map +1 -0
- package/packages/workflows/dist/runtime/time.js +42 -0
- package/packages/workflows/dist/runtime/time.js.map +1 -0
- package/packages/workflows/dist/store/catalog-records.d.ts +18 -0
- package/packages/workflows/dist/store/catalog-records.d.ts.map +1 -0
- package/packages/workflows/dist/store/catalog-records.js +59 -0
- package/packages/workflows/dist/store/catalog-records.js.map +1 -0
- package/packages/workflows/dist/store/contracts.d.ts +149 -0
- package/packages/workflows/dist/store/contracts.d.ts.map +1 -0
- package/packages/workflows/dist/store/contracts.js +2 -0
- package/packages/workflows/dist/store/contracts.js.map +1 -0
- package/packages/workflows/dist/store/draft-writes.d.ts +7 -0
- package/packages/workflows/dist/store/draft-writes.d.ts.map +1 -0
- package/packages/workflows/dist/store/draft-writes.js +18 -0
- package/packages/workflows/dist/store/draft-writes.js.map +1 -0
- package/packages/workflows/dist/store/index.d.ts +55 -0
- package/packages/workflows/dist/store/index.d.ts.map +1 -0
- package/packages/workflows/dist/store/index.js +650 -0
- package/packages/workflows/dist/store/index.js.map +1 -0
- package/packages/workflows/dist/store/list-query.d.ts +13 -0
- package/packages/workflows/dist/store/list-query.d.ts.map +1 -0
- package/packages/workflows/dist/store/list-query.js +20 -0
- package/packages/workflows/dist/store/list-query.js.map +1 -0
- package/packages/workflows/dist/store/row-mappers.d.ts +206 -0
- package/packages/workflows/dist/store/row-mappers.d.ts.map +1 -0
- package/packages/workflows/dist/store/row-mappers.js +262 -0
- package/packages/workflows/dist/store/row-mappers.js.map +1 -0
- package/packages/workflows/dist/store/schema.d.ts +13 -0
- package/packages/workflows/dist/store/schema.d.ts.map +1 -0
- package/packages/workflows/dist/store/schema.js +458 -0
- package/packages/workflows/dist/store/schema.js.map +1 -0
- package/packages/workflows/dist/store/write-values.d.ts +18 -0
- package/packages/workflows/dist/store/write-values.d.ts.map +1 -0
- package/packages/workflows/dist/store/write-values.js +227 -0
- package/packages/workflows/dist/store/write-values.js.map +1 -0
- package/packages/workflows/dist/types/index.d.ts +1202 -0
- package/packages/workflows/dist/types/index.d.ts.map +1 -0
- package/packages/workflows/dist/types/index.js +8 -0
- package/packages/workflows/dist/types/index.js.map +1 -0
- package/packages/workflows/dist/validation/diagnostics.d.ts +27 -0
- package/packages/workflows/dist/validation/diagnostics.d.ts.map +1 -0
- package/packages/workflows/dist/validation/diagnostics.js +104 -0
- package/packages/workflows/dist/validation/diagnostics.js.map +1 -0
- package/packages/workflows/dist/validation/graph-cycles.d.ts +4 -0
- package/packages/workflows/dist/validation/graph-cycles.d.ts.map +1 -0
- package/packages/workflows/dist/validation/graph-cycles.js +130 -0
- package/packages/workflows/dist/validation/graph-cycles.js.map +1 -0
- package/packages/workflows/dist/validation/graph-edges.d.ts +5 -0
- package/packages/workflows/dist/validation/graph-edges.d.ts.map +1 -0
- package/packages/workflows/dist/validation/graph-edges.js +48 -0
- package/packages/workflows/dist/validation/graph-edges.js.map +1 -0
- package/packages/workflows/dist/validation/graph-ports.d.ts +5 -0
- package/packages/workflows/dist/validation/graph-ports.d.ts.map +1 -0
- package/packages/workflows/dist/validation/graph-ports.js +55 -0
- package/packages/workflows/dist/validation/graph-ports.js.map +1 -0
- package/packages/workflows/dist/validation/index.d.ts +18 -0
- package/packages/workflows/dist/validation/index.d.ts.map +1 -0
- package/packages/workflows/dist/validation/index.js +175 -0
- package/packages/workflows/dist/validation/index.js.map +1 -0
- package/packages/workflows/dist/validation/json-schema.d.ts +12 -0
- package/packages/workflows/dist/validation/json-schema.d.ts.map +1 -0
- package/packages/workflows/dist/validation/json-schema.js +556 -0
- package/packages/workflows/dist/validation/json-schema.js.map +1 -0
- package/packages/workflows/dist/validation/registry-refs.d.ts +21 -0
- package/packages/workflows/dist/validation/registry-refs.d.ts.map +1 -0
- package/packages/workflows/dist/validation/registry-refs.js +283 -0
- package/packages/workflows/dist/validation/registry-refs.js.map +1 -0
- package/packages/workflows/dist/validation/retry-policy.d.ts +3 -0
- package/packages/workflows/dist/validation/retry-policy.d.ts.map +1 -0
- package/packages/workflows/dist/validation/retry-policy.js +114 -0
- package/packages/workflows/dist/validation/retry-policy.js.map +1 -0
- package/packages/workflows/dist/validation/schema-declarations.d.ts +5 -0
- package/packages/workflows/dist/validation/schema-declarations.d.ts.map +1 -0
- package/packages/workflows/dist/validation/schema-declarations.js +36 -0
- package/packages/workflows/dist/validation/schema-declarations.js.map +1 -0
- package/packages/workflows/dist/validation/state-access.d.ts +4 -0
- package/packages/workflows/dist/validation/state-access.d.ts.map +1 -0
- package/packages/workflows/dist/validation/state-access.js +121 -0
- package/packages/workflows/dist/validation/state-access.js.map +1 -0
- package/packages/workflows/dist/xstate/index.d.ts +73 -0
- package/packages/workflows/dist/xstate/index.d.ts.map +1 -0
- package/packages/workflows/dist/xstate/index.js +728 -0
- package/packages/workflows/dist/xstate/index.js.map +1 -0
- package/packages/workflows/package.json +23 -0
- package/dist/apps/chat/data/project-service.js +0 -1029
- package/dist/apps/chat-ui/assets/index-DWJnUye8.css +0 -1
- package/dist/apps/chat-ui/assets/index-exohEOUE.js +0 -228
- package/dist/apps/chat-vscode-web/assets/index-D1bpAUkR.js +0 -43
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import os from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
3
4
|
import { monitorEventLoopDelay } from "node:perf_hooks";
|
|
4
5
|
import { PiboSteeringUnavailableError } from "../../core/events.js";
|
|
5
6
|
import { OutputRenderSequencer, validRenderSequence } from "../../core/output-render-sequence.js";
|
|
@@ -12,7 +13,7 @@ import { summarizeSessionSignalStatus } from "../../signals/status.js";
|
|
|
12
13
|
import { PiboWebHttpError, readJsonBody, responseJson } from "../../web/http.js";
|
|
13
14
|
import { OutputCompactor } from "./output-compactor.js";
|
|
14
15
|
import { isLiveOnlyOutputEvent, isPersistableOutputEvent, isPiboOutputEvent } from "./output-event-policy.js";
|
|
15
|
-
import { chatRoomIdFromMetadata, isDefaultPiboRoom, isPiboRoomArchived, roomWorkspaceFromMetadata, withChatRoomId, withPiboRoomWorkspace, } from "./types/rooms.js";
|
|
16
|
+
import { chatRoomIdFromMetadata, comparePiboRoomsBySidebarOrder, isDefaultPiboRoom, isPiboRoomArchived, isPiboRoomPinned, piboRoomSidebarOrder, roomWorkspaceFromMetadata, withChatRoomId, withPiboRoomPinned, withPiboRoomSidebarOrder, withPiboRoomWorkspace, } from "./types/rooms.js";
|
|
16
17
|
import { chatStreamFramesFromOutputEvent, createChatStreamState, nextTransientChatStreamFrameId } from "./stream.js";
|
|
17
18
|
import { buildSessionNodes, buildTraceView, TRACE_PROJECTION_VERSION } from "./trace.js";
|
|
18
19
|
import { DEFAULT_TRACE_EVENTS_PAGE_SIZE, annotateTracePage, etagForVersion, estimateTraceViewBytes, traceCacheEstimatedBytes, liveSnapshotVersion, requestMatchesVersion, setTraceCache, traceProjectionStatus, traceCacheKey, withLiveSnapshots, withRawTraceTail, } from "./chat-trace-helpers.js";
|
|
@@ -39,7 +40,8 @@ import { ChatRoomService, PiboRoomHierarchyCycleError } from "./data/room-servic
|
|
|
39
40
|
import { ChatSessionQueryService } from "./data/session-query-service.js";
|
|
40
41
|
import { ChatTimelineQueryService } from "./data/timeline-query-service.js";
|
|
41
42
|
import { ChatHistoryQueryService } from "./data/history-query-service.js";
|
|
42
|
-
import {
|
|
43
|
+
import { ChatWorkflowSessionService, } from "./data/workflow-session-service.js";
|
|
44
|
+
import { migrateLegacyProjects } from "./data/legacy-project-migration.js";
|
|
43
45
|
import { PiboDataStore } from "../../data/pibo-store.js";
|
|
44
46
|
import { createDefaultPiboCronStore } from "../../cron/store.js";
|
|
45
47
|
import { createDefaultPiboLoopStore } from "../../loops/store.js";
|
|
@@ -56,12 +58,12 @@ import { responseChatSpeechProviders, responseChatSpeechSessionSpeak, responseCh
|
|
|
56
58
|
import { chatSettingsRoute, chatSettingsRouteInvalidatesBootstrapCatalog, chatSettingsRouteRequiresSameOrigin, handleChatSettingsRoute, } from "./chat-settings-routes.js";
|
|
57
59
|
import { chatCapabilityRoute, chatCapabilityRouteRequiresSameOrigin, handleChatCapabilityRoute, } from "./chat-capability-routes.js";
|
|
58
60
|
import { chatUserSkillRoute, chatUserSkillRouteRequiresSameOrigin, handleChatUserSkillRoute, syncChatUserSkills, } from "./chat-user-skill-routes.js";
|
|
59
|
-
import { CHAT_WEB_API_PREFIX, agentFolderResourceId, agentResourceId,
|
|
60
|
-
import {
|
|
61
|
+
import { CHAT_WEB_API_PREFIX, agentFolderResourceId, agentResourceId, roomResourcePath, sessionActionResource, sessionResourceId, sessionWorkflowResource, signalResource, workflowArchiveResourceId, workflowCatalogResourceId, workflowDraftActionResource, workflowDraftManualTriggerRunResource, workflowDraftResourceId, workflowDuplicateResourceId, workflowNextDraftResourceId, workflowPickerKind, workflowPromptAssetResourceId, workflowVersionResource, } from "./chat-api-routes.js";
|
|
62
|
+
import { buildStreamingFixtureSchedule, createAgentInput, createAgentUpdate, createRoomUpdate, createSessionUpdate, normalizeAgentArchived, normalizeAgentFolderName, normalizeClientTxnId, normalizeMessageDelivery, normalizeMessageText, normalizeParentRoomId, normalizeRoomDeleteConfirmation, normalizeRoomName, normalizeRoomTopic, normalizeRoomType, normalizeRoomWorkspace, normalizeSessionDeleteConfirmation, normalizeSessionTitle, normalizeStreamingFixtureCadenceMs, normalizeStreamingFixtureDeltas, normalizeStreamingFixtureMix, normalizeStreamingFixturePreludeMessages, normalizeStreamingFixturePreludeOnly, normalizeStreamingFixtureProfile, normalizeStreamingFixtureSuppressLiveDeltas, normalizeStreamingFixtureTraceSnapshots, normalizeStreamingFixtureToolInterleaving, resolveCreateSessionProfile, } from "./chat-request-normalizers.js";
|
|
61
63
|
import { ChatWorkflowArchiveStore, ChatWorkflowDraftStore, ChatWorkflowLifecycleEventStore, ChatWorkflowPromptAssetStore, ChatWorkflowPublishedVersionStore, ChatWorkflowTombstoneStore, hashWorkflowDefinitionJson, normalizeWorkflowPromptAssetLabel, sanitizeWorkflowDiagnostics, } from "./workflow-persistence.js";
|
|
62
|
-
import {
|
|
63
|
-
import {
|
|
64
|
-
import { STATIC_WORKFLOW_VERSION_CATALOG,
|
|
64
|
+
import { normalizeWorkflowHumanActionBody, workflowHumanActionDiagnosticResponse, workflowHumanActionLifecyclePayload, workflowHumanActionRuntimeDiagnostic, workflowHumanActionSubmittedLifecyclePayload, workflowPendingHumanActionFromToken, validateWorkflowHumanActionRequest, } from "./workflow-human-actions.js";
|
|
65
|
+
import { createWorkflowRunCurrent, createWorkflowSessionSnapshot, normalizeWorkflowSessionConfiguration, workflowVersionFromSnapshot, } from "./workflow-sessions.js";
|
|
66
|
+
import { STATIC_WORKFLOW_VERSION_CATALOG, buildWorkflowVersionCatalog, buildWorkflowVersionOptions, buildWorkflowCatalogInspect as buildWorkflowCatalogInspectWithServices, buildWorkflowCatalogList as buildWorkflowCatalogListWithServices, buildWorkflowVersionHistory, buildWorkflowVersionInspect as buildWorkflowVersionInspectWithServices, buildWorkflowVersionList as buildWorkflowVersionListWithServices, buildWorkflowVersionPicker, createPublishedWorkflowDefinition, selectWorkflowCatalogDisplayVersion, workflowDefinitionTags, workflowVersionPickerOptionFromCatalogRecord, } from "./workflow-catalog.js";
|
|
65
67
|
import { cloneJsonObject, isWorkflowValidationPipelineDiagnostic, normalizeWorkflowValidationTrigger, normalizeWorkflowVersionIntent, parseWorkflowDraftDefinitionFromPatch, summarizeWorkflowDiagnostics, withoutRawWorkflowIrParseDiagnostic, } from "./workflow-validation-helpers.js";
|
|
66
68
|
import { validateWorkflowEdgeAdapterOutputCompatibilityLike, validateWorkflowEdgeDirectCompatibilityLike, } from "./workflow-edge-compatibility.js";
|
|
67
69
|
import { runWorkflowManualTextTrigger, } from "./workflow-manual-trigger-runtime.js";
|
|
@@ -236,6 +238,13 @@ function createReliabilityStore(path) {
|
|
|
236
238
|
function createDataStore(options) {
|
|
237
239
|
return new PiboDataStore(options.dataStorePath, { payloadRootDir: options.dataPayloadRootDir });
|
|
238
240
|
}
|
|
241
|
+
function workflowStorePath(options, dataStore) {
|
|
242
|
+
if (options.workflowStorePath)
|
|
243
|
+
return options.workflowStorePath;
|
|
244
|
+
if (dataStore.path === ":memory:")
|
|
245
|
+
return ":memory:";
|
|
246
|
+
return join(dirname(dataStore.path), "pibo-workflows.sqlite");
|
|
247
|
+
}
|
|
239
248
|
function resolveVscodeWebUrl(value) {
|
|
240
249
|
const trimmed = value?.trim();
|
|
241
250
|
if (!trimmed)
|
|
@@ -875,17 +884,6 @@ function requireRoom(state, roomId, webSession, action = "read") {
|
|
|
875
884
|
}
|
|
876
885
|
return room;
|
|
877
886
|
}
|
|
878
|
-
function listSharedProjects(state, _webSession, options = {}) {
|
|
879
|
-
return state.projectService.listProjects(options);
|
|
880
|
-
}
|
|
881
|
-
function requireSharedProject(state, _webSession, projectId, options = {}) {
|
|
882
|
-
try {
|
|
883
|
-
return state.projectService.requireProject(projectId, options);
|
|
884
|
-
}
|
|
885
|
-
catch {
|
|
886
|
-
throw new PiboWebHttpError("Project not found", 404);
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
887
|
function createSharedChatSession(context, webSession, profile, room) {
|
|
890
888
|
const normalSessions = sessionsInRoom(listSharedSessions(context), room.id)
|
|
891
889
|
.filter((session) => !session.parentId && !isChatWebSessionArchived(session) && !isChatWebSessionPinned(session));
|
|
@@ -897,72 +895,56 @@ function createSharedChatSession(context, webSession, profile, room) {
|
|
|
897
895
|
metadata: withChatWebSessionSidebarOrder(withChatRoomId(undefined, room.id), nextChatWebSessionSidebarOrder(normalSessions)),
|
|
898
896
|
});
|
|
899
897
|
}
|
|
900
|
-
function
|
|
901
|
-
const
|
|
898
|
+
function createWorkflowSession(input) {
|
|
899
|
+
const normalSessions = sessionsInRoom(listSharedSessions(input.context), input.room.id)
|
|
900
|
+
.filter((session) => !session.parentId && !isChatWebSessionArchived(session) && !isChatWebSessionPinned(session));
|
|
902
901
|
const session = input.context.channelContext.createSession({
|
|
903
902
|
channel: CHAT_WEB_CHANNEL,
|
|
904
903
|
kind: "chat",
|
|
905
904
|
profile: input.profile,
|
|
906
|
-
workspace: input.
|
|
905
|
+
workspace: input.workspace ?? roomWorkspaceFromMetadata(input.room.metadata) ?? getDefaultPiboWorkspace(),
|
|
907
906
|
...(input.title ? { title: input.title } : {}),
|
|
908
|
-
...(input.configuration
|
|
909
|
-
metadata: withWorkflowSessionKind({
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
...(input.configuration ? { projectWorkflowConfiguration: input.configuration } : {}),
|
|
915
|
-
}, "main_workflow"),
|
|
907
|
+
...(input.configuration.model ? { activeModel: input.configuration.model } : {}),
|
|
908
|
+
metadata: withWorkflowSessionKind(withChatWebSessionSidebarOrder({
|
|
909
|
+
...withChatRoomId(undefined, input.room.id),
|
|
910
|
+
workflowId: input.workflow.id,
|
|
911
|
+
workflowVersion: input.workflow.version,
|
|
912
|
+
}, nextChatWebSessionSidebarOrder(normalSessions)), "main_workflow"),
|
|
916
913
|
});
|
|
917
|
-
input.state.
|
|
918
|
-
projectId: input.project.id,
|
|
914
|
+
const workflowSession = input.state.workflowService.addWorkflowSession({
|
|
919
915
|
piboSessionId: session.id,
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
title: session.title,
|
|
924
|
-
state: input.configuredWorkflow ? "configured" : undefined,
|
|
916
|
+
workflowId: input.workflow.id,
|
|
917
|
+
workflowVersion: input.workflow.version,
|
|
918
|
+
state: "configured",
|
|
925
919
|
configuration: input.configuration,
|
|
926
920
|
});
|
|
927
921
|
input.state.sessionQuery.upsertSession(session);
|
|
928
|
-
return session;
|
|
922
|
+
return { session, workflowSession };
|
|
929
923
|
}
|
|
930
|
-
function
|
|
924
|
+
function resolveWorkflowSelection(state, workflowIdValue, workflowVersionValue, options = {}) {
|
|
931
925
|
if (options.requireExplicitWorkflowId && (workflowIdValue === undefined || workflowIdValue === null || workflowIdValue === "")) {
|
|
932
926
|
throw new PiboWebHttpError("Workflow id is required", 400);
|
|
933
927
|
}
|
|
934
|
-
const workflowId =
|
|
935
|
-
const workflowVersion =
|
|
936
|
-
if (options.requireExplicitVersion && !workflowVersion)
|
|
928
|
+
const workflowId = normalizeWorkflowId(workflowIdValue);
|
|
929
|
+
const workflowVersion = normalizeWorkflowVersion(workflowVersionValue);
|
|
930
|
+
if (options.requireExplicitVersion && !workflowVersion)
|
|
937
931
|
throw new PiboWebHttpError("Workflow version is required", 400);
|
|
938
|
-
|
|
939
|
-
const candidates = buildProjectWorkflowVersionCatalog(state).filter((option) => option.id === workflowId);
|
|
932
|
+
const candidates = buildWorkflowVersionCatalog(state).filter((option) => option.id === workflowId);
|
|
940
933
|
const selected = candidates.find((option) => workflowVersion === undefined || option.version === workflowVersion);
|
|
941
|
-
if (!selected)
|
|
934
|
+
if (!selected)
|
|
942
935
|
throw new PiboWebHttpError(`Unknown workflow version: ${workflowId}${workflowVersion ? `@${workflowVersion}` : ""}`, 400);
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
}
|
|
947
|
-
if (selected.status !== "published") {
|
|
936
|
+
if (selected.status === "archived")
|
|
937
|
+
throw new PiboWebHttpError(`Workflow version '${selected.id}@${selected.version}' is archived and cannot create a Workflow Session`, 400);
|
|
938
|
+
if (selected.status !== "published")
|
|
948
939
|
throw new PiboWebHttpError(`Workflow version '${selected.id}@${selected.version}' is not published`, 400);
|
|
949
|
-
}
|
|
950
940
|
return workflowVersionPickerOptionFromCatalogRecord({ ...selected, status: "published" });
|
|
951
941
|
}
|
|
952
|
-
function
|
|
953
|
-
const workflowId = normalizeProjectWorkflowId(value);
|
|
954
|
-
if (workflowId !== "simple-chat")
|
|
955
|
-
throw new PiboWebHttpError("Only the simple-chat workflow is available in V1", 400);
|
|
956
|
-
return workflowId;
|
|
957
|
-
}
|
|
958
|
-
function normalizeProjectWorkflowId(value) {
|
|
959
|
-
if (value === undefined || value === null || value === "")
|
|
960
|
-
return "simple-chat";
|
|
942
|
+
function normalizeWorkflowId(value) {
|
|
961
943
|
if (typeof value !== "string" || !value.trim())
|
|
962
|
-
throw new PiboWebHttpError("Workflow id
|
|
944
|
+
throw new PiboWebHttpError("Workflow id is required", 400);
|
|
963
945
|
return value.trim();
|
|
964
946
|
}
|
|
965
|
-
function
|
|
947
|
+
function normalizeWorkflowVersion(value) {
|
|
966
948
|
if (value === undefined || value === null || value === "")
|
|
967
949
|
return undefined;
|
|
968
950
|
if (typeof value !== "string" || !value.trim())
|
|
@@ -1034,18 +1016,14 @@ function requireWorkflowDeleteConfirmation(value, workflowId) {
|
|
|
1034
1016
|
throw new PiboWebHttpError(`Type "${workflowId}" to delete this workflow.`, 400);
|
|
1035
1017
|
}
|
|
1036
1018
|
}
|
|
1037
|
-
|
|
1038
|
-
"title",
|
|
1039
|
-
"archived",
|
|
1040
|
-
]);
|
|
1041
|
-
function validateProjectWorkflowSnapshotForStart(snapshot, input) {
|
|
1019
|
+
function validateWorkflowSnapshotForStart(snapshot, input) {
|
|
1042
1020
|
const diagnostics = sanitizeWorkflowDiagnostics(validateWorkflowDefinitionForV2(snapshot.effectiveDefinition, input));
|
|
1043
1021
|
return {
|
|
1044
1022
|
diagnostics,
|
|
1045
1023
|
validation: summarizeWorkflowDiagnostics(diagnostics, "before_workflow_start"),
|
|
1046
1024
|
};
|
|
1047
1025
|
}
|
|
1048
|
-
function
|
|
1026
|
+
function updateWorkflowRunSessionMetadata(input) {
|
|
1049
1027
|
if (input.session.metadata?.workflowRunId === input.workflowRunId)
|
|
1050
1028
|
return;
|
|
1051
1029
|
const updateSession = input.context.channelContext.updateSession;
|
|
@@ -1576,8 +1554,8 @@ function requireValidatedWorkflowDraft(state, context, webSession, draftId, trig
|
|
|
1576
1554
|
return serializeWorkflowDraft(record);
|
|
1577
1555
|
}
|
|
1578
1556
|
function duplicateWorkflowIntoDraft(state, webSession, workflowIdValue, workflowVersionValue) {
|
|
1579
|
-
const workflowId =
|
|
1580
|
-
const workflowVersion =
|
|
1557
|
+
const workflowId = normalizeWorkflowId(workflowIdValue);
|
|
1558
|
+
const workflowVersion = normalizeWorkflowVersion(workflowVersionValue);
|
|
1581
1559
|
const published = selectPublishedWorkflowVersion(state, workflowId, workflowVersion);
|
|
1582
1560
|
if (!published)
|
|
1583
1561
|
throw new PiboWebHttpError("Published workflow version not found", 404);
|
|
@@ -1628,8 +1606,8 @@ function duplicateWorkflowIntoDraft(state, webSession, workflowIdValue, workflow
|
|
|
1628
1606
|
return serializeWorkflowDraft(draft);
|
|
1629
1607
|
}
|
|
1630
1608
|
function createNextVersionDraftFromPublishedWorkflow(state, webSession, workflowIdValue, workflowVersionValue) {
|
|
1631
|
-
const workflowId =
|
|
1632
|
-
const workflowVersion =
|
|
1609
|
+
const workflowId = normalizeWorkflowId(workflowIdValue);
|
|
1610
|
+
const workflowVersion = normalizeWorkflowVersion(workflowVersionValue);
|
|
1633
1611
|
const published = selectPublishedWorkflowVersion(state, workflowId, workflowVersion);
|
|
1634
1612
|
if (!published)
|
|
1635
1613
|
throw new PiboWebHttpError("Published workflow version not found", 404);
|
|
@@ -1686,7 +1664,7 @@ function createNextVersionDraftFromPublishedWorkflow(state, webSession, workflow
|
|
|
1686
1664
|
return { draft: serializeWorkflowDraft(draft), reused: false };
|
|
1687
1665
|
}
|
|
1688
1666
|
function archiveWorkflowIdentity(state, context, webSession, workflowIdValue, reasonValue) {
|
|
1689
|
-
const workflowId =
|
|
1667
|
+
const workflowId = normalizeWorkflowId(workflowIdValue);
|
|
1690
1668
|
const catalog = buildWorkflowCatalogList(state, context, webSession, { includeArchived: true });
|
|
1691
1669
|
const workflow = catalog.workflows.find((record) => record.id === workflowId);
|
|
1692
1670
|
if (!workflow)
|
|
@@ -1716,7 +1694,7 @@ function archiveWorkflowIdentity(state, context, webSession, workflowIdValue, re
|
|
|
1716
1694
|
return { workflow: archivedWorkflow, archiveState };
|
|
1717
1695
|
}
|
|
1718
1696
|
function deleteWorkflowIdentity(state, context, webSession, workflowIdValue, body) {
|
|
1719
|
-
const workflowId =
|
|
1697
|
+
const workflowId = normalizeWorkflowId(workflowIdValue);
|
|
1720
1698
|
const catalog = buildWorkflowCatalogList(state, context, webSession, { includeArchived: true });
|
|
1721
1699
|
const workflow = catalog.workflows.find((record) => record.id === workflowId);
|
|
1722
1700
|
if (!workflow)
|
|
@@ -1749,7 +1727,7 @@ function deleteWorkflowIdentity(state, context, webSession, workflowIdValue, bod
|
|
|
1749
1727
|
return { workflowId, deleted: true, tombstone };
|
|
1750
1728
|
}
|
|
1751
1729
|
function selectPublishedWorkflowVersion(state, workflowId, version) {
|
|
1752
|
-
const options =
|
|
1730
|
+
const options = buildWorkflowVersionOptions(state).filter((option) => option.id === workflowId);
|
|
1753
1731
|
const selected = version ? options.find((option) => option.version === version) : options[0];
|
|
1754
1732
|
if (!selected)
|
|
1755
1733
|
return undefined;
|
|
@@ -1917,7 +1895,9 @@ function normalizeWorkflowDraftManualTriggerRunBody(body) {
|
|
|
1917
1895
|
throw new PiboWebHttpError("Manual trigger node id is required", 400);
|
|
1918
1896
|
if (typeof body.input !== "string")
|
|
1919
1897
|
throw new PiboWebHttpError("Manual trigger input must be text", 400);
|
|
1920
|
-
|
|
1898
|
+
if (body.roomId !== undefined && typeof body.roomId !== "string")
|
|
1899
|
+
throw new PiboWebHttpError("Room id must be a string", 400);
|
|
1900
|
+
return { triggerNodeId, input: body.input, roomId: typeof body.roomId === "string" ? body.roomId.trim() || undefined : undefined, workspace: body.workspace === undefined ? undefined : normalizeRoomWorkspace(body.workspace) };
|
|
1921
1901
|
}
|
|
1922
1902
|
function resolveWorkflowRuntimeProfile(input) {
|
|
1923
1903
|
const profile = input.context.channelContext.getProfiles?.().find((candidate) => candidate.name === input.requestedId || candidate.aliases.includes(input.requestedId));
|
|
@@ -2204,7 +2184,7 @@ function validateWorkflowNestedNodeLike(nodeId, node, input, diagnostics) {
|
|
|
2204
2184
|
const workflowId = typeof node.workflowId === "string" ? node.workflowId.trim() : undefined;
|
|
2205
2185
|
const workflowVersion = typeof node.workflowVersion === "string" ? node.workflowVersion.trim() : undefined;
|
|
2206
2186
|
const selected = workflowId
|
|
2207
|
-
?
|
|
2187
|
+
? buildWorkflowVersionOptions(input.state).find((option) => option.id === workflowId && (!workflowVersion || option.version === workflowVersion))
|
|
2208
2188
|
: undefined;
|
|
2209
2189
|
if (!selected) {
|
|
2210
2190
|
const registryRef = workflowId ? `${workflowId}${workflowVersion ? `@${workflowVersion}` : ""}` : undefined;
|
|
@@ -2424,7 +2404,7 @@ async function deleteSessionsForAgentProfile(state, context, webSession, profile
|
|
|
2424
2404
|
}
|
|
2425
2405
|
const orderedIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
|
|
2426
2406
|
for (const id of orderedIds) {
|
|
2427
|
-
await
|
|
2407
|
+
await deleteSession(id);
|
|
2428
2408
|
state.sessionQuery.deleteSessions([id]);
|
|
2429
2409
|
state.eventCommands.deleteSessions([id]);
|
|
2430
2410
|
}
|
|
@@ -2451,7 +2431,7 @@ async function deleteSessionSubtree(state, context, webSession, rootSession) {
|
|
|
2451
2431
|
}
|
|
2452
2432
|
const orderedIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
|
|
2453
2433
|
for (const id of orderedIds) {
|
|
2454
|
-
await
|
|
2434
|
+
await deleteSession(id);
|
|
2455
2435
|
state.sessionQuery.deleteSessions([id]);
|
|
2456
2436
|
state.eventCommands.deleteSessions([id]);
|
|
2457
2437
|
}
|
|
@@ -2492,7 +2472,7 @@ async function deleteRoomTree(state, context, webSession, room, confirmName) {
|
|
|
2492
2472
|
}
|
|
2493
2473
|
const orderedSessionIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
|
|
2494
2474
|
for (const id of orderedSessionIds) {
|
|
2495
|
-
await
|
|
2475
|
+
await deleteSession(id);
|
|
2496
2476
|
state.sessionQuery.deleteSessions([id]);
|
|
2497
2477
|
state.eventCommands.deleteSessions([id]);
|
|
2498
2478
|
}
|
|
@@ -2705,6 +2685,48 @@ async function resolveContextBuildRuntime(context, runtimeInstanceId) {
|
|
|
2705
2685
|
function indexSharedSessions(sessionQuery, sessions) {
|
|
2706
2686
|
sessionQuery.upsertSessionsIfChanged(sessions);
|
|
2707
2687
|
}
|
|
2688
|
+
function nextChatWebRoomSidebarOrder(rooms) {
|
|
2689
|
+
return rooms.reduce((maximum, room) => {
|
|
2690
|
+
const createdOrder = Date.parse(room.createdAt) || 0;
|
|
2691
|
+
return Math.max(maximum, piboRoomSidebarOrder(room) ?? createdOrder);
|
|
2692
|
+
}, 0) + 1;
|
|
2693
|
+
}
|
|
2694
|
+
function reorderChatWebRoom(input) {
|
|
2695
|
+
if (input.room.parentRoomId || input.targetRoom.parentRoomId) {
|
|
2696
|
+
throw new PiboWebHttpError("Only top-level rooms can be reordered", 400);
|
|
2697
|
+
}
|
|
2698
|
+
if (isDefaultPiboRoom(input.room) || isDefaultPiboRoom(input.targetRoom)) {
|
|
2699
|
+
throw new PiboWebHttpError("Shared Chat cannot be reordered", 400);
|
|
2700
|
+
}
|
|
2701
|
+
if (isPiboRoomArchived(input.room) || isPiboRoomArchived(input.targetRoom)) {
|
|
2702
|
+
throw new PiboWebHttpError("Archived rooms cannot be reordered", 400);
|
|
2703
|
+
}
|
|
2704
|
+
const pinned = isPiboRoomPinned(input.room);
|
|
2705
|
+
if (pinned !== isPiboRoomPinned(input.targetRoom)) {
|
|
2706
|
+
throw new PiboWebHttpError("Pinned and unpinned rooms cannot be reordered together", 400);
|
|
2707
|
+
}
|
|
2708
|
+
const ordered = input.state.roomService.listRooms()
|
|
2709
|
+
.filter((room) => !room.parentRoomId && !isDefaultPiboRoom(room) && !isPiboRoomArchived(room) && isPiboRoomPinned(room) === pinned)
|
|
2710
|
+
.sort(comparePiboRoomsBySidebarOrder);
|
|
2711
|
+
const movedIndex = ordered.findIndex((room) => room.id === input.room.id);
|
|
2712
|
+
const targetIndex = ordered.findIndex((room) => room.id === input.targetRoom.id);
|
|
2713
|
+
if (movedIndex < 0 || targetIndex < 0)
|
|
2714
|
+
throw new PiboWebHttpError("Room ordering target not found", 404);
|
|
2715
|
+
if (movedIndex === targetIndex)
|
|
2716
|
+
return ordered.map((room) => room.id);
|
|
2717
|
+
const [moved] = ordered.splice(movedIndex, 1);
|
|
2718
|
+
const remainingTargetIndex = ordered.findIndex((room) => room.id === input.targetRoom.id);
|
|
2719
|
+
ordered.splice(input.position === "before" ? remainingTargetIndex : remainingTargetIndex + 1, 0, moved);
|
|
2720
|
+
const orderBase = nextChatWebRoomSidebarOrder(ordered) + ordered.length - 1;
|
|
2721
|
+
for (const [index, room] of ordered.entries()) {
|
|
2722
|
+
const updated = input.state.roomService.updateRoom(room.id, {
|
|
2723
|
+
metadata: withPiboRoomSidebarOrder(room.metadata, orderBase - index),
|
|
2724
|
+
});
|
|
2725
|
+
if (!updated)
|
|
2726
|
+
throw new PiboWebHttpError("Room not found", 404);
|
|
2727
|
+
}
|
|
2728
|
+
return ordered.map((room) => room.id);
|
|
2729
|
+
}
|
|
2708
2730
|
function nextChatWebSessionSidebarOrder(sessions) {
|
|
2709
2731
|
return sessions.reduce((maximum, session) => {
|
|
2710
2732
|
const createdOrder = Date.parse(session.createdAt) || 0;
|
|
@@ -3221,284 +3243,75 @@ function createEventStream(input) {
|
|
|
3221
3243
|
},
|
|
3222
3244
|
});
|
|
3223
3245
|
}
|
|
3224
|
-
|
|
3225
|
-
const
|
|
3226
|
-
const
|
|
3227
|
-
let storedProjectSessions = input.state.projectService
|
|
3228
|
-
.listProjectSessions(selectedProject.id, { includeArchived: input.includeArchived })
|
|
3229
|
-
.filter((projectSession) => projectSession.workflowId === "simple-chat");
|
|
3230
|
-
if (selectedProject.id === sharedDefaultProject.id && storedProjectSessions.length === 0) {
|
|
3231
|
-
const session = createProjectChatSession({
|
|
3232
|
-
state: input.state,
|
|
3233
|
-
context: input.context,
|
|
3234
|
-
webSession: input.webSession,
|
|
3235
|
-
project: sharedDefaultProject,
|
|
3236
|
-
profile: input.defaultProfile,
|
|
3237
|
-
workflowId: "simple-chat",
|
|
3238
|
-
});
|
|
3239
|
-
storedProjectSessions = [input.state.projectService.getProjectSession(session.id)];
|
|
3240
|
-
}
|
|
3241
|
-
const projectSessions = storedProjectSessions;
|
|
3242
|
-
const rootSessions = projectSessions
|
|
3243
|
-
.map((projectSession) => input.context.channelContext.getSession(projectSession.piboSessionId))
|
|
3244
|
-
.filter((session) => Boolean(session));
|
|
3245
|
-
const sessions = collectProjectSessionTreeSessions(rootSessions, listSharedSessions(input.context));
|
|
3246
|
-
const requestedSession = input.piboSessionId ? sessions.find((session) => session.id === input.piboSessionId) : undefined;
|
|
3247
|
-
const selectedSession = requestedSession ?? sessions.find((session) => session.id === selectedProject.currentMainSessionId) ?? sessions[0];
|
|
3248
|
-
indexSharedSessions(input.state.sessionQuery, sessions);
|
|
3249
|
-
const nodes = await buildSessionNodes(sessions, input.state.sessionQuery.listSessions(), selectedProject.projectFolder, new Map(), { skipPiMetadataFallback: true });
|
|
3250
|
-
applyProjectSessionArchiveState(nodes, new Map(projectSessions.map((projectSession) => [projectSession.piboSessionId, Boolean(projectSession.archived)])));
|
|
3251
|
-
return {
|
|
3252
|
-
identity: input.webSession.authSession.identity,
|
|
3253
|
-
sharedDefaultProject,
|
|
3254
|
-
project: selectedProject,
|
|
3255
|
-
projects: listSharedProjects(input.state, input.webSession, { includeArchived: input.includeArchived }),
|
|
3256
|
-
projectSessions,
|
|
3257
|
-
workflowLifecycleEvents: [],
|
|
3258
|
-
...(selectedSession ? { session: selectedSession, selectedPiboSessionId: selectedSession.id } : {}),
|
|
3259
|
-
selectedProjectId: selectedProject.id,
|
|
3260
|
-
sessions: nodes,
|
|
3261
|
-
...(await loadBootstrapCatalog(input.state, input.context, input.webSession)),
|
|
3262
|
-
};
|
|
3263
|
-
}
|
|
3264
|
-
function collectProjectSessionTreeSessions(rootSessions, candidateSessions) {
|
|
3265
|
-
const sessionsById = new Map(rootSessions.map((session) => [session.id, session]));
|
|
3266
|
-
let changed = true;
|
|
3267
|
-
while (changed) {
|
|
3268
|
-
changed = false;
|
|
3269
|
-
for (const session of candidateSessions) {
|
|
3270
|
-
if (sessionsById.has(session.id))
|
|
3271
|
-
continue;
|
|
3272
|
-
if (!session.parentId || !sessionsById.has(session.parentId))
|
|
3273
|
-
continue;
|
|
3274
|
-
sessionsById.set(session.id, session);
|
|
3275
|
-
changed = true;
|
|
3276
|
-
}
|
|
3277
|
-
}
|
|
3278
|
-
return [...sessionsById.values()].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
3279
|
-
}
|
|
3280
|
-
function enrichProjectSessionWorkflowDefinitionLink(state, projectSession) {
|
|
3281
|
-
if (!isProjectWorkflowBackedSession(projectSession))
|
|
3282
|
-
return projectSession;
|
|
3283
|
-
const snapshot = state.projectService.getWorkflowSessionSnapshotForSession(projectSession.piboSessionId);
|
|
3284
|
-
const workflowId = projectSession.workflowId;
|
|
3285
|
-
const workflowVersion = projectSession.workflowVersion ?? snapshot?.workflow.version;
|
|
3246
|
+
function enrichWorkflowSession(state, workflowSession) {
|
|
3247
|
+
const snapshot = state.workflowService.getWorkflowSessionSnapshotForSession(workflowSession.piboSessionId);
|
|
3248
|
+
const workflowVersion = workflowSession.workflowVersion ?? snapshot?.workflow.version;
|
|
3286
3249
|
const catalogRecord = workflowVersion
|
|
3287
|
-
?
|
|
3250
|
+
? buildWorkflowVersionCatalog(state).find((record) => record.id === workflowSession.workflowId && record.version === workflowVersion)
|
|
3288
3251
|
: undefined;
|
|
3289
3252
|
const snapshotHash = snapshot?.workflow.effectiveDefinitionHash ?? snapshot?.deletedDefinitionFallback.effectiveDefinitionHash;
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
const
|
|
3304
|
-
const
|
|
3305
|
-
|
|
3306
|
-
...projectSession,
|
|
3307
|
-
workflowDefinitionLink: {
|
|
3308
|
-
status: "snapshot_only_definition_deleted",
|
|
3309
|
-
workflowId,
|
|
3310
|
-
...(workflowVersion ? { workflowVersion } : {}),
|
|
3311
|
-
title: fallback?.title ?? snapshot?.workflow.title ?? projectSession.title ?? workflowId,
|
|
3312
|
-
...(definitionHash ? { definitionHash } : {}),
|
|
3313
|
-
tombstoneLabel: fallback?.tombstoneLabel ?? "Definition deleted or no longer available in the live Workflow catalog.",
|
|
3314
|
-
},
|
|
3315
|
-
};
|
|
3316
|
-
}
|
|
3317
|
-
function enrichProjectSessionWorkflowWaitTokens(state, projectSession) {
|
|
3318
|
-
if (!projectSession.workflowRunId)
|
|
3319
|
-
return projectSession;
|
|
3320
|
-
const waitTokens = state.projectService.listProjectWorkflowWaitTokens({
|
|
3321
|
-
projectId: projectSession.projectId,
|
|
3322
|
-
piboSessionId: projectSession.piboSessionId,
|
|
3323
|
-
workflowRunId: projectSession.workflowRunId,
|
|
3324
|
-
status: "pending",
|
|
3325
|
-
limit: 20,
|
|
3326
|
-
});
|
|
3327
|
-
if (!waitTokens.length)
|
|
3328
|
-
return projectSession;
|
|
3253
|
+
const workflowDefinitionLink = catalogRecord && catalogRecord.status !== "deleted"
|
|
3254
|
+
? { status: "live", workflowId: workflowSession.workflowId, workflowVersion: catalogRecord.version, title: catalogRecord.title, ...(snapshotHash ? { definitionHash: snapshotHash } : {}), href: workflowDefinitionViewerPath(catalogRecord.id, catalogRecord.version) }
|
|
3255
|
+
: { status: "snapshot_only_definition_deleted", workflowId: workflowSession.workflowId, ...(workflowVersion ? { workflowVersion } : {}), title: snapshot?.deletedDefinitionFallback.title ?? snapshot?.workflow.title ?? workflowSession.workflowId, ...(snapshotHash ? { definitionHash: snapshotHash } : {}), tombstoneLabel: snapshot?.deletedDefinitionFallback.tombstoneLabel ?? "No published catalog version is available. Inspection uses the immutable Workflow snapshot." };
|
|
3256
|
+
const waitTokens = workflowSession.workflowRunId ? state.workflowService.listWorkflowWaitTokens({ piboSessionId: workflowSession.piboSessionId, workflowRunId: workflowSession.workflowRunId, status: "pending", limit: 20 }) : [];
|
|
3257
|
+
return { ...workflowSession, workflowDefinitionLink, ...(waitTokens.length ? { pendingHumanActions: waitTokens.map((token) => workflowPendingHumanActionFromToken(token, WORKFLOW_HUMAN_ACTION_REF_OPTIONS)) } : {}) };
|
|
3258
|
+
}
|
|
3259
|
+
function inspectWorkflowSession(state, context, piboSessionId) {
|
|
3260
|
+
requireSharedSession(context, piboSessionId);
|
|
3261
|
+
const link = state.workflowService.getWorkflowSession(piboSessionId);
|
|
3262
|
+
if (!link)
|
|
3263
|
+
throw new PiboWebHttpError("Workflow session not found", 404);
|
|
3264
|
+
const workflowSession = enrichWorkflowSession(state, link);
|
|
3265
|
+
const snapshot = state.workflowService.getWorkflowSessionSnapshotForSession(piboSessionId);
|
|
3266
|
+
const run = state.workflowService.getWorkflowRunForSession(piboSessionId);
|
|
3267
|
+
const workflowRunId = run?.id ?? workflowSession.workflowRunId;
|
|
3268
|
+
const definitionSnapshot = run?.definitionSnapshotId ? state.workflowService.runtimeStore.getDefinitionSnapshot(run.definitionSnapshotId) : undefined;
|
|
3329
3269
|
return {
|
|
3330
|
-
|
|
3331
|
-
|
|
3270
|
+
workflowSession,
|
|
3271
|
+
...(definitionSnapshot ? { definitionSnapshot } : {}),
|
|
3272
|
+
...(snapshot ? { snapshot } : {}),
|
|
3273
|
+
...(run ? { run } : {}),
|
|
3274
|
+
waitTokens: state.workflowService.listWorkflowWaitTokens({ piboSessionId, ...(workflowRunId ? { workflowRunId } : {}), limit: 200 }),
|
|
3275
|
+
humanActions: state.workflowService.listWorkflowHumanActions({ piboSessionId, ...(workflowRunId ? { workflowRunId } : {}), limit: 200 }),
|
|
3276
|
+
nodeAttempts: workflowRunId ? state.workflowService.runtimeStore.listNodeAttempts({ workflowRunId, limit: 200 }) : [],
|
|
3277
|
+
edgeTransfers: workflowRunId ? state.workflowService.runtimeStore.listEdgeTransfers({ workflowRunId, limit: 200 }) : [],
|
|
3278
|
+
lifecycleEvents: [...new Map([
|
|
3279
|
+
...state.workflowLifecycleEventStore.listEvents({ piboSessionId, limit: 200 }),
|
|
3280
|
+
...(workflowRunId ? state.workflowLifecycleEventStore.listEvents({ workflowRunId, limit: 200 }) : []),
|
|
3281
|
+
].map((event) => [event.id, event])).values()].sort((left, right) => right.createdAt.localeCompare(left.createdAt) || right.id.localeCompare(left.id)),
|
|
3332
3282
|
};
|
|
3333
3283
|
}
|
|
3334
|
-
function
|
|
3335
|
-
|
|
3336
|
-
const
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
severity: "error",
|
|
3345
|
-
path: "$.workflowRunId",
|
|
3346
|
-
hint: "Start the configured workflow session before submitting human actions.",
|
|
3347
|
-
}], 409, undefined, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3348
|
-
}
|
|
3349
|
-
const normalized = normalizeProjectWorkflowHumanActionBody(input.body);
|
|
3350
|
-
if (normalized.diagnostics.length) {
|
|
3351
|
-
return projectWorkflowHumanActionDiagnosticResponse("Human action request is invalid", normalized.diagnostics, 400, undefined, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3352
|
-
}
|
|
3284
|
+
function submitWorkflowHumanAction(input) {
|
|
3285
|
+
requireSharedSession(input.context, input.piboSessionId);
|
|
3286
|
+
const workflowSession = input.state.workflowService.getWorkflowSession(input.piboSessionId);
|
|
3287
|
+
if (!workflowSession)
|
|
3288
|
+
throw new PiboWebHttpError("Workflow session not found", 404);
|
|
3289
|
+
if (!workflowSession.workflowRunId)
|
|
3290
|
+
return workflowHumanActionDiagnosticResponse("Workflow session has no workflow run to resolve", [{ code: "WorkflowRuntimeError.workflowRunMissing", message: "This Workflow session has not started a run.", severity: "error", path: "$.workflowRunId", hint: "Start the configured Workflow session before submitting human actions." }], 409, undefined, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3291
|
+
const normalized = normalizeWorkflowHumanActionBody(input.body);
|
|
3292
|
+
if (normalized.diagnostics.length)
|
|
3293
|
+
return workflowHumanActionDiagnosticResponse("Human action request is invalid", normalized.diagnostics, 400, undefined, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3353
3294
|
const request = normalized.request;
|
|
3354
|
-
const waitToken = input.state.
|
|
3355
|
-
const validation =
|
|
3356
|
-
projectSession,
|
|
3357
|
-
waitToken,
|
|
3358
|
-
request,
|
|
3359
|
-
humanActionOptions: WORKFLOW_HUMAN_ACTION_REF_OPTIONS,
|
|
3360
|
-
});
|
|
3295
|
+
const waitToken = input.state.workflowService.getWorkflowWaitToken(request.waitTokenId);
|
|
3296
|
+
const validation = validateWorkflowHumanActionRequest({ workflowSession, waitToken, request, humanActionOptions: WORKFLOW_HUMAN_ACTION_REF_OPTIONS });
|
|
3361
3297
|
if (validation.diagnostics.length) {
|
|
3362
|
-
const responseWaitToken = waitToken && validation.expiredAt
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
piboSessionId: session.id,
|
|
3366
|
-
workflowRunId: projectSession.workflowRunId,
|
|
3367
|
-
waitTokenId: waitToken.id,
|
|
3368
|
-
resolvedAt: validation.checkedAt,
|
|
3369
|
-
}).waitToken
|
|
3370
|
-
: waitToken;
|
|
3371
|
-
recordWorkflowLifecycleEvent(input.state, input.webSession, {
|
|
3372
|
-
type: "workflow.human_action.submitted",
|
|
3373
|
-
workflowId: projectSession.workflowId,
|
|
3374
|
-
...(projectSession.workflowVersion ? { workflowVersion: projectSession.workflowVersion } : {}),
|
|
3375
|
-
projectId: project.id,
|
|
3376
|
-
piboSessionId: session.id,
|
|
3377
|
-
workflowRunId: projectSession.workflowRunId,
|
|
3378
|
-
status: "blocked",
|
|
3379
|
-
diagnostics: validation.diagnostics,
|
|
3380
|
-
payload: projectWorkflowHumanActionLifecyclePayload(request),
|
|
3381
|
-
});
|
|
3382
|
-
return projectWorkflowHumanActionDiagnosticResponse("Human action was rejected by wait-token validation", validation.diagnostics, validation.httpStatus, responseWaitToken, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3298
|
+
const responseWaitToken = waitToken && validation.expiredAt ? input.state.workflowService.expireWorkflowWaitToken({ piboSessionId: input.piboSessionId, workflowRunId: workflowSession.workflowRunId, waitTokenId: waitToken.id, resolvedAt: validation.checkedAt }).waitToken : waitToken;
|
|
3299
|
+
recordWorkflowLifecycleEvent(input.state, input.webSession, { type: "workflow.human_action.submitted", workflowId: workflowSession.workflowId, workflowVersion: workflowSession.workflowVersion, piboSessionId: input.piboSessionId, workflowRunId: workflowSession.workflowRunId, status: "blocked", diagnostics: validation.diagnostics, payload: workflowHumanActionLifecyclePayload(request) });
|
|
3300
|
+
return workflowHumanActionDiagnosticResponse("Human action was rejected by wait-token validation", validation.diagnostics, validation.httpStatus, responseWaitToken, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3383
3301
|
}
|
|
3384
3302
|
try {
|
|
3385
|
-
const result = input.state.
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
workflowRunId: projectSession.workflowRunId,
|
|
3389
|
-
waitTokenId: request.waitTokenId,
|
|
3390
|
-
...(validation.actionRef?.id ? { actionId: validation.actionRef.id } : {}),
|
|
3391
|
-
kind: validation.actionKind,
|
|
3392
|
-
actor: {
|
|
3393
|
-
userId: input.webSession.authSession.identity.userId,
|
|
3394
|
-
...(input.webSession.authSession.identity.email ? { email: input.webSession.authSession.identity.email } : {}),
|
|
3395
|
-
},
|
|
3396
|
-
...(request.payload !== undefined ? { payload: request.payload } : {}),
|
|
3397
|
-
});
|
|
3398
|
-
const enrichedProjectSession = enrichProjectSessionWorkflowWaitTokens(input.state, enrichProjectSessionWorkflowDefinitionLink(input.state, result.projectSession));
|
|
3399
|
-
recordWorkflowLifecycleEvent(input.state, input.webSession, {
|
|
3400
|
-
type: "workflow.human_action.submitted",
|
|
3401
|
-
workflowId: result.projectSession.workflowId,
|
|
3402
|
-
...(result.projectSession.workflowVersion ? { workflowVersion: result.projectSession.workflowVersion } : {}),
|
|
3403
|
-
projectId: project.id,
|
|
3404
|
-
piboSessionId: session.id,
|
|
3405
|
-
workflowRunId: result.run.id,
|
|
3406
|
-
status: "submitted",
|
|
3407
|
-
diagnostics: [],
|
|
3408
|
-
payload: projectWorkflowHumanActionSubmittedLifecyclePayload(result.waitToken.id, result.action),
|
|
3409
|
-
});
|
|
3410
|
-
return responseJson({
|
|
3411
|
-
ok: true,
|
|
3412
|
-
projectSession: enrichedProjectSession,
|
|
3413
|
-
waitToken: result.waitToken,
|
|
3414
|
-
action: result.action,
|
|
3415
|
-
run: result.run,
|
|
3416
|
-
diagnostics: [],
|
|
3417
|
-
}, { status: result.action.kind === "cancel" ? 200 : 202 });
|
|
3303
|
+
const result = input.state.workflowService.resolveWorkflowHumanAction({ piboSessionId: input.piboSessionId, workflowRunId: workflowSession.workflowRunId, waitTokenId: request.waitTokenId, ...(validation.actionRef?.id ? { actionId: validation.actionRef.id } : {}), kind: validation.actionKind, actor: { userId: input.webSession.authSession.identity.userId, ...(input.webSession.authSession.identity.email ? { email: input.webSession.authSession.identity.email } : {}) }, ...(request.payload !== undefined ? { payload: request.payload } : {}) });
|
|
3304
|
+
recordWorkflowLifecycleEvent(input.state, input.webSession, { type: "workflow.human_action.submitted", workflowId: result.workflowSession.workflowId, workflowVersion: result.workflowSession.workflowVersion, piboSessionId: input.piboSessionId, workflowRunId: result.run.id, status: "submitted", diagnostics: [], payload: workflowHumanActionSubmittedLifecyclePayload(result.waitToken.id, result.action) });
|
|
3305
|
+
return responseJson({ ok: true, workflowSession: enrichWorkflowSession(input.state, result.workflowSession), waitToken: result.waitToken, action: result.action, run: result.run, diagnostics: [] }, { status: result.action.kind === "cancel" ? 200 : 202 });
|
|
3418
3306
|
}
|
|
3419
3307
|
catch (error) {
|
|
3420
|
-
const diagnostics = [
|
|
3421
|
-
|
|
3422
|
-
type: "workflow.human_action.submitted",
|
|
3423
|
-
workflowId: projectSession.workflowId,
|
|
3424
|
-
...(projectSession.workflowVersion ? { workflowVersion: projectSession.workflowVersion } : {}),
|
|
3425
|
-
projectId: project.id,
|
|
3426
|
-
piboSessionId: session.id,
|
|
3427
|
-
workflowRunId: projectSession.workflowRunId,
|
|
3428
|
-
status: "blocked",
|
|
3429
|
-
diagnostics,
|
|
3430
|
-
payload: projectWorkflowHumanActionLifecyclePayload(request),
|
|
3431
|
-
});
|
|
3432
|
-
const responseWaitToken = input.state.projectService.getProjectWorkflowWaitToken(request.waitTokenId) ?? waitToken;
|
|
3433
|
-
return projectWorkflowHumanActionDiagnosticResponse("Human action was rejected by wait-token validation", diagnostics, 409, responseWaitToken, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3308
|
+
const diagnostics = [workflowHumanActionRuntimeDiagnostic(error, request.waitTokenId)];
|
|
3309
|
+
return workflowHumanActionDiagnosticResponse("Human action was rejected by wait-token validation", diagnostics, 409, input.state.workflowService.getWorkflowWaitToken(request.waitTokenId) ?? waitToken, WORKFLOW_HUMAN_ACTION_REF_OPTIONS);
|
|
3434
3310
|
}
|
|
3435
3311
|
}
|
|
3436
|
-
function isProjectWorkflowBackedSession(projectSession) {
|
|
3437
|
-
return Boolean(projectSession.workflowRunId) || projectSession.state === "workflow" || projectSession.workflowId !== "simple-chat";
|
|
3438
|
-
}
|
|
3439
3312
|
function workflowDefinitionViewerPath(workflowId, workflowVersion) {
|
|
3440
3313
|
return `${CHAT_WEB_MOUNT_PATH}/workflows/view/${encodeURIComponent(workflowId)}/${encodeURIComponent(workflowVersion)}`;
|
|
3441
3314
|
}
|
|
3442
|
-
function applyProjectSessionArchiveState(nodes, archivedBySessionId) {
|
|
3443
|
-
for (const node of nodes) {
|
|
3444
|
-
const archived = archivedBySessionId.get(node.piboSessionId);
|
|
3445
|
-
if (archived !== undefined)
|
|
3446
|
-
node.archived = archived;
|
|
3447
|
-
applyProjectSessionArchiveState(node.children, archivedBySessionId);
|
|
3448
|
-
}
|
|
3449
|
-
}
|
|
3450
|
-
async function sendProjectMessage(input) {
|
|
3451
|
-
const text = normalizeMessageText(input.body.text);
|
|
3452
|
-
const delivery = normalizeMessageDelivery(input.body.delivery);
|
|
3453
|
-
const clientTxnId = normalizeClientTxnId(input.body.clientTxnId);
|
|
3454
|
-
if (typeof input.body.piboSessionId !== "string")
|
|
3455
|
-
throw new PiboWebHttpError("Project session is required", 400);
|
|
3456
|
-
const selectedSession = requireSharedSession(input.context, input.body.piboSessionId);
|
|
3457
|
-
const projectSession = input.state.projectService.getProjectSession(selectedSession.id);
|
|
3458
|
-
if (!projectSession)
|
|
3459
|
-
throw new PiboWebHttpError("Project session not found", 404);
|
|
3460
|
-
requireSharedProject(input.state, input.webSession, projectSession.projectId);
|
|
3461
|
-
const actorId = auditActorIdFor(input.webSession);
|
|
3462
|
-
const duplicate = clientTxnId ? input.state.eventCommands.findByClientTxn(undefined, actorId, clientTxnId) : undefined;
|
|
3463
|
-
if (duplicate)
|
|
3464
|
-
return responseJson({ duplicate: true, event: duplicate });
|
|
3465
|
-
const accepted = input.state.eventCommands.appendEvent({
|
|
3466
|
-
piboSessionId: selectedSession.id,
|
|
3467
|
-
eventType: "user.message.accepted",
|
|
3468
|
-
actorType: "user",
|
|
3469
|
-
actorId,
|
|
3470
|
-
clientTxnId,
|
|
3471
|
-
retentionClass: "chat_message",
|
|
3472
|
-
payload: {
|
|
3473
|
-
type: "user.message.accepted",
|
|
3474
|
-
piboSessionId: selectedSession.id,
|
|
3475
|
-
projectId: projectSession.projectId,
|
|
3476
|
-
text,
|
|
3477
|
-
delivery,
|
|
3478
|
-
...(clientTxnId ? { clientTxnId } : {}),
|
|
3479
|
-
},
|
|
3480
|
-
});
|
|
3481
|
-
for (const listener of input.state.liveListeners)
|
|
3482
|
-
listener(accepted);
|
|
3483
|
-
const messageId = clientTxnId ?? randomUUID();
|
|
3484
|
-
try {
|
|
3485
|
-
const output = await input.context.channelContext.emit({
|
|
3486
|
-
type: "message",
|
|
3487
|
-
piboSessionId: selectedSession.id,
|
|
3488
|
-
id: messageId,
|
|
3489
|
-
text,
|
|
3490
|
-
delivery,
|
|
3491
|
-
source: "user",
|
|
3492
|
-
});
|
|
3493
|
-
return responseJson({ accepted, output });
|
|
3494
|
-
}
|
|
3495
|
-
catch (error) {
|
|
3496
|
-
if (error instanceof PiboSteeringUnavailableError || error instanceof AgentRuntimeBindingMissingError) {
|
|
3497
|
-
throw new PiboWebHttpError(error.message, 409);
|
|
3498
|
-
}
|
|
3499
|
-
throw error;
|
|
3500
|
-
}
|
|
3501
|
-
}
|
|
3502
3315
|
function startChatStreamingFixture(input) {
|
|
3503
3316
|
const requestedRoomId = typeof input.body.roomId === "string" ? input.body.roomId : undefined;
|
|
3504
3317
|
const selectedSession = resolveRequestedSession(input.state, input.context, input.webSession, input.defaultProfile, typeof input.body.piboSessionId === "string" ? input.body.piboSessionId : undefined, requestedRoomId);
|
|
@@ -3727,6 +3540,11 @@ export function createChatWebApp(options = {}) {
|
|
|
3727
3540
|
const defaultProfile = options.defaultProfile ?? "base";
|
|
3728
3541
|
const dataStore = createDataStore(options);
|
|
3729
3542
|
const reliabilityStore = createReliabilityStore(options.reliabilityStorePath);
|
|
3543
|
+
const workflowService = new ChatWorkflowSessionService(workflowStorePath(options, dataStore));
|
|
3544
|
+
if (dataStore.path !== ":memory:" && workflowService.path !== ":memory:") {
|
|
3545
|
+
migrateLegacyProjects({ dataStore, workflowService });
|
|
3546
|
+
}
|
|
3547
|
+
const workflowCatalogStore = workflowService.catalogDataStore;
|
|
3730
3548
|
const eventLoopDelay = monitorEventLoopDelay({ resolution: 20 });
|
|
3731
3549
|
eventLoopDelay.enable();
|
|
3732
3550
|
const state = {
|
|
@@ -3736,7 +3554,7 @@ export function createChatWebApp(options = {}) {
|
|
|
3736
3554
|
eventCommands: new ChatEventCommandService(dataStore),
|
|
3737
3555
|
readState: new ChatReadStateService(dataStore),
|
|
3738
3556
|
roomService: new ChatRoomService(dataStore),
|
|
3739
|
-
|
|
3557
|
+
workflowService,
|
|
3740
3558
|
agentStore: createAgentStore(options.agentStorePath),
|
|
3741
3559
|
reliabilityStore,
|
|
3742
3560
|
cronStore: createDefaultPiboCronStore({ path: options.cronStorePath }),
|
|
@@ -3762,12 +3580,12 @@ export function createChatWebApp(options = {}) {
|
|
|
3762
3580
|
globalRoot: options.userSkillGlobalRoot ?? os.homedir(),
|
|
3763
3581
|
workspaceRoot: options.userSkillWorkspaceRoot ?? process.cwd(),
|
|
3764
3582
|
}),
|
|
3765
|
-
workflowDraftStore: new ChatWorkflowDraftStore(
|
|
3766
|
-
workflowPublishedVersionStore: new ChatWorkflowPublishedVersionStore(
|
|
3767
|
-
workflowArchiveStore: new ChatWorkflowArchiveStore(
|
|
3768
|
-
workflowTombstoneStore: new ChatWorkflowTombstoneStore(
|
|
3769
|
-
workflowLifecycleEventStore: new ChatWorkflowLifecycleEventStore(
|
|
3770
|
-
workflowPromptAssetStore: new ChatWorkflowPromptAssetStore(
|
|
3583
|
+
workflowDraftStore: new ChatWorkflowDraftStore(workflowCatalogStore),
|
|
3584
|
+
workflowPublishedVersionStore: new ChatWorkflowPublishedVersionStore(workflowCatalogStore),
|
|
3585
|
+
workflowArchiveStore: new ChatWorkflowArchiveStore(workflowCatalogStore),
|
|
3586
|
+
workflowTombstoneStore: new ChatWorkflowTombstoneStore(workflowCatalogStore),
|
|
3587
|
+
workflowLifecycleEventStore: new ChatWorkflowLifecycleEventStore(workflowCatalogStore),
|
|
3588
|
+
workflowPromptAssetStore: new ChatWorkflowPromptAssetStore(workflowCatalogStore),
|
|
3771
3589
|
telemetryRetentionMaintenance: {},
|
|
3772
3590
|
integrations,
|
|
3773
3591
|
};
|
|
@@ -3788,7 +3606,7 @@ export function createChatWebApp(options = {}) {
|
|
|
3788
3606
|
state.subscribedContext = undefined;
|
|
3789
3607
|
state.eventLoopDelay.disable();
|
|
3790
3608
|
state.outputPersistenceRetries.dispose();
|
|
3791
|
-
state.
|
|
3609
|
+
state.workflowService.close();
|
|
3792
3610
|
state.agentStore.close();
|
|
3793
3611
|
state.reliabilityStore.close();
|
|
3794
3612
|
state.cronStore.close();
|
|
@@ -4049,306 +3867,66 @@ export function createChatWebApp(options = {}) {
|
|
|
4049
3867
|
if (response)
|
|
4050
3868
|
return response;
|
|
4051
3869
|
}
|
|
4052
|
-
if (url.pathname === `${CHAT_WEB_API_PREFIX}/
|
|
4053
|
-
const webSession = await requireSession(request, context);
|
|
4054
|
-
return responseJson(await buildProjectsBootstrap({
|
|
4055
|
-
state,
|
|
4056
|
-
context,
|
|
4057
|
-
webSession,
|
|
4058
|
-
defaultProfile,
|
|
4059
|
-
projectId: url.searchParams.get("projectId") || undefined,
|
|
4060
|
-
piboSessionId: url.searchParams.get("piboSessionId") || undefined,
|
|
4061
|
-
includeArchived: parseBooleanSearchParam(url, "includeArchived"),
|
|
4062
|
-
}));
|
|
4063
|
-
}
|
|
4064
|
-
if (url.pathname === `${CHAT_WEB_API_PREFIX}/projects/message` && request.method === "POST") {
|
|
3870
|
+
if (url.pathname === `${CHAT_WEB_API_PREFIX}/workflow-sessions` && request.method === "POST") {
|
|
4065
3871
|
requireSameOriginJsonRequest(request);
|
|
4066
3872
|
const webSession = await requireSession(request, context);
|
|
4067
3873
|
const body = await readJsonBody(request);
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
const
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
createFolder: body.createFolder === true,
|
|
4084
|
-
});
|
|
4085
|
-
return responseJson({ project }, { status: 201 });
|
|
4086
|
-
}
|
|
4087
|
-
catch (error) {
|
|
4088
|
-
throw new PiboWebHttpError(error instanceof Error ? error.message : String(error), 400);
|
|
4089
|
-
}
|
|
4090
|
-
}
|
|
4091
|
-
const projectResource = projectResourcePath(url.pathname);
|
|
4092
|
-
if (projectResource && projectResource.child === undefined && request.method === "PATCH") {
|
|
4093
|
-
requireSameOriginJsonRequest(request);
|
|
4094
|
-
const webSession = await requireSession(request, context);
|
|
4095
|
-
const body = await readJsonBody(request);
|
|
4096
|
-
try {
|
|
4097
|
-
const existingProject = requireSharedProject(state, webSession, projectResource.projectId, { includeArchived: true });
|
|
4098
|
-
if (existingProject.metadata.default === true)
|
|
4099
|
-
throw new PiboWebHttpError("Project Manager cannot be changed", 400);
|
|
4100
|
-
const project = state.projectService.updateProject(projectResource.projectId, {
|
|
4101
|
-
...(body.name !== undefined ? { name: normalizeRoomName(body.name) } : {}),
|
|
4102
|
-
...(body.description !== undefined ? { description: normalizeProjectDescription(body.description) ?? null } : {}),
|
|
4103
|
-
...(body.archived !== undefined ? { archived: normalizeProjectArchived(body.archived) } : {}),
|
|
4104
|
-
});
|
|
4105
|
-
if (!project)
|
|
4106
|
-
throw new PiboWebHttpError("Project not found", 404);
|
|
4107
|
-
return responseJson({ project });
|
|
4108
|
-
}
|
|
4109
|
-
catch (error) {
|
|
4110
|
-
if (error instanceof PiboWebHttpError)
|
|
4111
|
-
throw error;
|
|
4112
|
-
throw new PiboWebHttpError(error instanceof Error ? error.message : String(error), 400);
|
|
4113
|
-
}
|
|
4114
|
-
}
|
|
4115
|
-
if (projectResource && projectResource.child === undefined && request.method === "DELETE") {
|
|
4116
|
-
requireSameOriginJsonRequest(request);
|
|
4117
|
-
const webSession = await requireSession(request, context);
|
|
4118
|
-
const body = await readJsonBody(request);
|
|
4119
|
-
try {
|
|
4120
|
-
const project = requireSharedProject(state, webSession, projectResource.projectId, { includeArchived: true });
|
|
4121
|
-
if (project.metadata.default === true)
|
|
4122
|
-
throw new PiboWebHttpError("Project Manager cannot be deleted", 400);
|
|
4123
|
-
return responseJson(state.projectService.deleteProject(projectResource.projectId, {
|
|
4124
|
-
confirmName: normalizeRoomDeleteConfirmation(body.confirmName),
|
|
4125
|
-
deleteFiles: body.deleteFiles === true,
|
|
4126
|
-
}));
|
|
4127
|
-
}
|
|
4128
|
-
catch (error) {
|
|
4129
|
-
if (error instanceof PiboWebHttpError)
|
|
4130
|
-
throw error;
|
|
4131
|
-
throw new PiboWebHttpError(error instanceof Error ? error.message : String(error), 400);
|
|
4132
|
-
}
|
|
3874
|
+
const room = typeof body.roomId === "string" && body.roomId.trim() ? requireRoom(state, body.roomId.trim(), webSession, "write") : state.roomService.ensureDefaultRoom();
|
|
3875
|
+
const workspace = body.workspace === undefined ? undefined : normalizeRoomWorkspace(body.workspace);
|
|
3876
|
+
const profile = resolveCreateSessionProfile(context, defaultProfile, body.profile);
|
|
3877
|
+
const workflow = resolveWorkflowSelection(state, body.workflowId, body.workflowVersion, { requireExplicitWorkflowId: true, requireExplicitVersion: true });
|
|
3878
|
+
const published = resolvePublishedWorkflowDefinitionForProfile(state, workflow, profile);
|
|
3879
|
+
const baseDefinition = cloneJsonObject(published.definition);
|
|
3880
|
+
const configuration = normalizeWorkflowSessionConfiguration(body, baseDefinition);
|
|
3881
|
+
const validation = validatePublishedWorkflowBoundary({ state, context, webSession, definition: baseDefinition, trigger: "before_workflow_session_creation" });
|
|
3882
|
+
recordWorkflowLifecycleEvent(state, webSession, { type: "workflow.validation.completed", workflowId: workflow.id, workflowVersion: workflow.version, status: validation.validation.ok ? "accepted" : "blocked", validation: validation.validation, diagnostics: validation.diagnostics, payload: { trigger: validation.validation.trigger, boundary: "workflow_session_creation" } });
|
|
3883
|
+
if (!validation.validation.ok)
|
|
3884
|
+
return workflowValidationBlockedResponse("Workflow version has validation errors and cannot create a Workflow Session", validation, { workflow });
|
|
3885
|
+
const created = createWorkflowSession({ state, context, room, workspace, profile, workflow, title: normalizeSessionTitle(body.title) ?? undefined, configuration });
|
|
3886
|
+
const snapshot = state.workflowService.saveWorkflowSessionSnapshot(createWorkflowSessionSnapshot({ webSession, session: created.session, workflow: published, baseDefinition, configuration, validation }));
|
|
3887
|
+
recordWorkflowLifecycleEvent(state, webSession, { type: "workflow.session.created", workflowId: workflow.id, workflowVersion: workflow.version, piboSessionId: created.session.id, status: "accepted", validation: validation.validation, diagnostics: validation.diagnostics, payload: { snapshotId: snapshot.id, profile, roomId: room.id } });
|
|
3888
|
+
return responseJson({ session: created.session, workflowSession: enrichWorkflowSession(state, created.workflowSession), workflow, configuration, snapshot, validation: validation.validation, diagnostics: validation.diagnostics }, { status: 201 });
|
|
4133
3889
|
}
|
|
4134
|
-
const
|
|
4135
|
-
if (
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
const body = await readJsonBody(request);
|
|
4139
|
-
return submitProjectWorkflowHumanAction({
|
|
4140
|
-
state,
|
|
4141
|
-
context,
|
|
4142
|
-
webSession,
|
|
4143
|
-
projectId: workflowHumanActionResource.projectId,
|
|
4144
|
-
piboSessionId: workflowHumanActionResource.piboSessionId,
|
|
4145
|
-
body,
|
|
4146
|
-
});
|
|
3890
|
+
const workflowResource = sessionWorkflowResource(url.pathname);
|
|
3891
|
+
if (workflowResource && workflowResource.action === undefined && request.method === "GET") {
|
|
3892
|
+
await requireSession(request, context);
|
|
3893
|
+
return responseJson(inspectWorkflowSession(state, context, workflowResource.piboSessionId));
|
|
4147
3894
|
}
|
|
4148
|
-
if (
|
|
3895
|
+
if (workflowResource?.action === "human-actions" && request.method === "POST") {
|
|
4149
3896
|
requireSameOriginJsonRequest(request);
|
|
4150
3897
|
const webSession = await requireSession(request, context);
|
|
4151
|
-
|
|
4152
|
-
const project = requireSharedProject(state, webSession, projectResource.projectId);
|
|
4153
|
-
const profile = resolveCreateSessionProfile(context, defaultProfile, body.profile);
|
|
4154
|
-
const workflowSelection = resolveProjectWorkflowSelection(state, body.workflowId, body.workflowVersion, { requireExplicitWorkflowId: true, requireExplicitVersion: true });
|
|
4155
|
-
const publishedWorkflow = resolvePublishedWorkflowDefinitionForProfile(state, workflowSelection, profile);
|
|
4156
|
-
const baseDefinition = cloneJsonObject(publishedWorkflow.definition);
|
|
4157
|
-
const configuration = normalizeProjectWorkflowSessionConfiguration(body, baseDefinition);
|
|
4158
|
-
const validation = validatePublishedWorkflowBoundary({
|
|
4159
|
-
state,
|
|
4160
|
-
context,
|
|
4161
|
-
webSession,
|
|
4162
|
-
definition: baseDefinition,
|
|
4163
|
-
trigger: "before_project_session_creation",
|
|
4164
|
-
});
|
|
4165
|
-
recordWorkflowLifecycleEvent(state, webSession, {
|
|
4166
|
-
type: "workflow.validation.completed",
|
|
4167
|
-
workflowId: workflowSelection.id,
|
|
4168
|
-
workflowVersion: workflowSelection.version,
|
|
4169
|
-
projectId: project.id,
|
|
4170
|
-
status: validation.validation.ok ? "accepted" : "blocked",
|
|
4171
|
-
validation: validation.validation,
|
|
4172
|
-
diagnostics: validation.diagnostics,
|
|
4173
|
-
payload: { trigger: validation.validation.trigger, boundary: "project_session_creation" },
|
|
4174
|
-
});
|
|
4175
|
-
if (!validation.validation.ok) {
|
|
4176
|
-
return workflowValidationBlockedResponse("Workflow version has validation errors and cannot be used to create a Project session", validation, { workflow: workflowSelection });
|
|
4177
|
-
}
|
|
4178
|
-
const session = createProjectChatSession({
|
|
4179
|
-
state,
|
|
4180
|
-
context,
|
|
4181
|
-
webSession,
|
|
4182
|
-
project,
|
|
4183
|
-
profile,
|
|
4184
|
-
workflowId: workflowSelection.id,
|
|
4185
|
-
workflowVersion: workflowSelection.version,
|
|
4186
|
-
title: normalizeSessionTitle(body.title) ?? undefined,
|
|
4187
|
-
configuredWorkflow: true,
|
|
4188
|
-
configuration,
|
|
4189
|
-
});
|
|
4190
|
-
const snapshot = state.projectService.saveWorkflowSessionSnapshot(createProjectWorkflowSessionSnapshot({
|
|
4191
|
-
webSession,
|
|
4192
|
-
project,
|
|
4193
|
-
session,
|
|
4194
|
-
workflow: publishedWorkflow,
|
|
4195
|
-
baseDefinition,
|
|
4196
|
-
configuration,
|
|
4197
|
-
validation,
|
|
4198
|
-
}));
|
|
4199
|
-
const projectSession = state.projectService.getProjectSession(session.id);
|
|
4200
|
-
recordWorkflowLifecycleEvent(state, webSession, {
|
|
4201
|
-
type: "project.workflow_session.created",
|
|
4202
|
-
workflowId: workflowSelection.id,
|
|
4203
|
-
workflowVersion: workflowSelection.version,
|
|
4204
|
-
projectId: project.id,
|
|
4205
|
-
piboSessionId: session.id,
|
|
4206
|
-
status: "accepted",
|
|
4207
|
-
validation: validation.validation,
|
|
4208
|
-
diagnostics: validation.diagnostics,
|
|
4209
|
-
payload: { snapshotId: snapshot.id, profile },
|
|
4210
|
-
});
|
|
4211
|
-
return responseJson({ session, projectSession, workflow: workflowSelection, configuration, snapshot, validation: validation.validation, diagnostics: validation.diagnostics }, { status: 201 });
|
|
3898
|
+
return submitWorkflowHumanAction({ state, context, webSession, piboSessionId: workflowResource.piboSessionId, body: await readJsonBody(request) });
|
|
4212
3899
|
}
|
|
4213
|
-
|
|
4214
|
-
if (workflowSessionStart && request.method === "POST") {
|
|
3900
|
+
if (workflowResource?.action === "start" && request.method === "POST") {
|
|
4215
3901
|
requireSameOriginJsonRequest(request);
|
|
4216
3902
|
const webSession = await requireSession(request, context);
|
|
4217
|
-
const session = requireSharedSession(context,
|
|
4218
|
-
const
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
const snapshot = state.projectService.getWorkflowSessionSnapshotForSession(session.id);
|
|
3903
|
+
const session = requireSharedSession(context, workflowResource.piboSessionId);
|
|
3904
|
+
const workflowSession = state.workflowService.getWorkflowSession(session.id);
|
|
3905
|
+
if (!workflowSession)
|
|
3906
|
+
throw new PiboWebHttpError("Workflow session not found", 404);
|
|
3907
|
+
const snapshot = state.workflowService.getWorkflowSessionSnapshotForSession(session.id);
|
|
4223
3908
|
if (!snapshot)
|
|
4224
|
-
throw new PiboWebHttpError("
|
|
4225
|
-
const
|
|
4226
|
-
if (
|
|
4227
|
-
const
|
|
4228
|
-
if (
|
|
4229
|
-
|
|
4230
|
-
return responseJson({
|
|
4231
|
-
projectSession,
|
|
4232
|
-
workflow: workflowSelection,
|
|
4233
|
-
snapshot,
|
|
4234
|
-
run: existingRun,
|
|
4235
|
-
alreadyStarted: true,
|
|
4236
|
-
validation: existingRun.validation ?? summarizeWorkflowDiagnostics([], "before_workflow_start"),
|
|
4237
|
-
diagnostics: [],
|
|
4238
|
-
message: "Workflow run already exists for this Project session.",
|
|
4239
|
-
}, { status: 200 });
|
|
3909
|
+
throw new PiboWebHttpError("Workflow session snapshot not found", 409);
|
|
3910
|
+
const workflow = workflowVersionFromSnapshot(snapshot);
|
|
3911
|
+
if (workflowSession.workflowRunId) {
|
|
3912
|
+
const run = state.workflowService.getWorkflowRun(workflowSession.workflowRunId);
|
|
3913
|
+
if (run) {
|
|
3914
|
+
updateWorkflowRunSessionMetadata({ state, context, session, workflowRunId: run.id });
|
|
3915
|
+
return responseJson({ workflowSession: enrichWorkflowSession(state, workflowSession), run, snapshot, workflow, alreadyStarted: true, validation: run.validation ?? summarizeWorkflowDiagnostics([], "before_workflow_start"), diagnostics: [], message: "Workflow run already exists for this Workflow Session." });
|
|
4240
3916
|
}
|
|
4241
3917
|
}
|
|
4242
|
-
const validation =
|
|
4243
|
-
recordWorkflowLifecycleEvent(state, webSession, {
|
|
4244
|
-
type: "workflow.validation.completed",
|
|
4245
|
-
workflowId: workflowSelection.id,
|
|
4246
|
-
workflowVersion: workflowSelection.version,
|
|
4247
|
-
projectId: project.id,
|
|
4248
|
-
piboSessionId: session.id,
|
|
4249
|
-
workflowRunId: projectSession.workflowRunId,
|
|
4250
|
-
status: validation.validation.ok ? "accepted" : "blocked",
|
|
4251
|
-
validation: validation.validation,
|
|
4252
|
-
diagnostics: validation.diagnostics,
|
|
4253
|
-
payload: { trigger: validation.validation.trigger, boundary: "workflow_start", snapshotId: snapshot.id },
|
|
4254
|
-
});
|
|
3918
|
+
const validation = validateWorkflowSnapshotForStart(snapshot, { state, context, webSession });
|
|
3919
|
+
recordWorkflowLifecycleEvent(state, webSession, { type: "workflow.validation.completed", workflowId: workflow.id, workflowVersion: workflow.version, piboSessionId: session.id, workflowRunId: workflowSession.workflowRunId, status: validation.validation.ok ? "accepted" : "blocked", validation: validation.validation, diagnostics: validation.diagnostics, payload: { trigger: validation.validation.trigger, boundary: "workflow_start", snapshotId: snapshot.id } });
|
|
4255
3920
|
if (!validation.validation.ok) {
|
|
4256
|
-
recordWorkflowLifecycleEvent(state, webSession, {
|
|
4257
|
-
|
|
4258
|
-
workflowId: workflowSelection.id,
|
|
4259
|
-
workflowVersion: workflowSelection.version,
|
|
4260
|
-
projectId: project.id,
|
|
4261
|
-
piboSessionId: session.id,
|
|
4262
|
-
workflowRunId: projectSession.workflowRunId,
|
|
4263
|
-
status: "blocked",
|
|
4264
|
-
validation: validation.validation,
|
|
4265
|
-
diagnostics: validation.diagnostics,
|
|
4266
|
-
payload: { snapshotId: snapshot.id, profile: session.profile },
|
|
4267
|
-
});
|
|
4268
|
-
return workflowValidationBlockedResponse("Workflow session has validation errors and cannot be started", validation, { projectSession, workflow: workflowSelection });
|
|
4269
|
-
}
|
|
4270
|
-
const startResult = state.projectService.startWorkflowSessionRun({
|
|
4271
|
-
projectId: project.id,
|
|
4272
|
-
piboSessionId: session.id,
|
|
4273
|
-
runId: `wfr_${randomUUID()}`,
|
|
4274
|
-
workflowId: snapshot.workflow.id,
|
|
4275
|
-
workflowVersion: snapshot.workflow.version,
|
|
4276
|
-
snapshotId: snapshot.id,
|
|
4277
|
-
effectiveDefinitionHash: snapshot.workflow.effectiveDefinitionHash,
|
|
4278
|
-
current: createProjectWorkflowRunCurrent(snapshot.effectiveDefinition),
|
|
4279
|
-
inputValues: snapshot.inputValues,
|
|
4280
|
-
validation: validation.validation,
|
|
4281
|
-
});
|
|
4282
|
-
updateProjectWorkflowRunSessionMetadata({ state, context, session, workflowRunId: startResult.run.id });
|
|
4283
|
-
recordWorkflowLifecycleEvent(state, webSession, {
|
|
4284
|
-
type: "project.workflow_start.accepted",
|
|
4285
|
-
workflowId: workflowSelection.id,
|
|
4286
|
-
workflowVersion: workflowSelection.version,
|
|
4287
|
-
projectId: project.id,
|
|
4288
|
-
piboSessionId: session.id,
|
|
4289
|
-
workflowRunId: startResult.run.id,
|
|
4290
|
-
status: "accepted",
|
|
4291
|
-
validation: validation.validation,
|
|
4292
|
-
diagnostics: validation.diagnostics,
|
|
4293
|
-
payload: { snapshotId: snapshot.id, profile: session.profile, alreadyStarted: startResult.alreadyStarted },
|
|
4294
|
-
});
|
|
4295
|
-
if (!startResult.alreadyStarted) {
|
|
4296
|
-
recordWorkflowLifecycleEvent(state, webSession, {
|
|
4297
|
-
type: "workflow.run.status_changed",
|
|
4298
|
-
workflowId: workflowSelection.id,
|
|
4299
|
-
workflowVersion: workflowSelection.version,
|
|
4300
|
-
projectId: project.id,
|
|
4301
|
-
piboSessionId: session.id,
|
|
4302
|
-
workflowRunId: startResult.run.id,
|
|
4303
|
-
status: "changed",
|
|
4304
|
-
validation: validation.validation,
|
|
4305
|
-
diagnostics: validation.diagnostics,
|
|
4306
|
-
payload: { snapshotId: snapshot.id, state: startResult.run.status, current: startResult.run.current },
|
|
4307
|
-
});
|
|
4308
|
-
}
|
|
4309
|
-
return responseJson({
|
|
4310
|
-
projectSession: startResult.projectSession,
|
|
4311
|
-
workflow: workflowSelection,
|
|
4312
|
-
snapshot,
|
|
4313
|
-
run: startResult.run,
|
|
4314
|
-
alreadyStarted: startResult.alreadyStarted,
|
|
4315
|
-
validation: validation.validation,
|
|
4316
|
-
diagnostics: validation.diagnostics,
|
|
4317
|
-
message: startResult.alreadyStarted ? "Workflow run already exists for this Project session." : "Workflow run started.",
|
|
4318
|
-
}, { status: startResult.alreadyStarted ? 200 : 202 });
|
|
4319
|
-
}
|
|
4320
|
-
if (projectResource && projectResource.child === "sessions" && request.method === "POST") {
|
|
4321
|
-
requireSameOriginJsonRequest(request);
|
|
4322
|
-
const webSession = await requireSession(request, context);
|
|
4323
|
-
const body = await readJsonBody(request);
|
|
4324
|
-
const project = requireSharedProject(state, webSession, projectResource.projectId);
|
|
4325
|
-
const profile = resolveCreateSessionProfile(context, defaultProfile, body.profile);
|
|
4326
|
-
const workflowId = normalizeLegacyProjectWorkflowId(body.workflowId);
|
|
4327
|
-
const session = createProjectChatSession({ state, context, webSession, project, profile, workflowId });
|
|
4328
|
-
return responseJson({ session, projectSession: state.projectService.getProjectSession(session.id) }, { status: 201 });
|
|
4329
|
-
}
|
|
4330
|
-
const projectSessionId = projectSessionResourceId(url.pathname);
|
|
4331
|
-
if (projectSessionId && request.method === "PATCH") {
|
|
4332
|
-
requireSameOriginJsonRequest(request);
|
|
4333
|
-
const webSession = await requireSession(request, context);
|
|
4334
|
-
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, projectSessionId);
|
|
4335
|
-
const body = await readJsonBody(request);
|
|
4336
|
-
assertProjectSessionPatchFields(body);
|
|
4337
|
-
const updateSession = context.channelContext.updateSession;
|
|
4338
|
-
if (!updateSession)
|
|
4339
|
-
throw new PiboWebHttpError("Session updates are not available", 501);
|
|
4340
|
-
const title = normalizeSessionTitle(body.title);
|
|
4341
|
-
let updated = selectedSession;
|
|
4342
|
-
if (title !== undefined) {
|
|
4343
|
-
const next = updateSession(selectedSession.id, { title });
|
|
4344
|
-
if (!next)
|
|
4345
|
-
throw new PiboWebHttpError("Session not found", 404);
|
|
4346
|
-
updated = next;
|
|
4347
|
-
state.sessionQuery.upsertSession(updated);
|
|
3921
|
+
recordWorkflowLifecycleEvent(state, webSession, { type: "workflow.start.blocked", workflowId: workflow.id, workflowVersion: workflow.version, piboSessionId: session.id, status: "blocked", validation: validation.validation, diagnostics: validation.diagnostics, payload: { snapshotId: snapshot.id, profile: session.profile } });
|
|
3922
|
+
return workflowValidationBlockedResponse("Workflow Session has validation errors and cannot be started", validation, { workflowSession, workflow });
|
|
4348
3923
|
}
|
|
4349
|
-
const
|
|
4350
|
-
|
|
4351
|
-
|
|
3924
|
+
const started = state.workflowService.startWorkflowSessionRun({ piboSessionId: session.id, runId: `wfr_${randomUUID()}`, workflowId: snapshot.workflow.id, workflowVersion: snapshot.workflow.version, snapshotId: snapshot.id, effectiveDefinitionHash: snapshot.workflow.effectiveDefinitionHash, current: createWorkflowRunCurrent(snapshot.effectiveDefinition), inputValues: snapshot.inputValues, validation: validation.validation });
|
|
3925
|
+
updateWorkflowRunSessionMetadata({ state, context, session, workflowRunId: started.run.id });
|
|
3926
|
+
recordWorkflowLifecycleEvent(state, webSession, { type: "workflow.start.accepted", workflowId: workflow.id, workflowVersion: workflow.version, piboSessionId: session.id, workflowRunId: started.run.id, status: "accepted", validation: validation.validation, diagnostics: validation.diagnostics, payload: { snapshotId: snapshot.id, profile: session.profile, alreadyStarted: started.alreadyStarted } });
|
|
3927
|
+
if (!started.alreadyStarted)
|
|
3928
|
+
recordWorkflowLifecycleEvent(state, webSession, { type: "workflow.run.status_changed", workflowId: workflow.id, workflowVersion: workflow.version, piboSessionId: session.id, workflowRunId: started.run.id, status: "changed", validation: validation.validation, diagnostics: validation.diagnostics, payload: { snapshotId: snapshot.id, state: started.run.status, current: started.run.current } });
|
|
3929
|
+
return responseJson({ workflowSession: enrichWorkflowSession(state, started.workflowSession), run: started.run, snapshot, workflow, alreadyStarted: started.alreadyStarted, validation: validation.validation, diagnostics: validation.diagnostics, message: started.alreadyStarted ? "Workflow run already exists for this Workflow Session." : "Workflow run recorded. General graph execution is not connected to this surface; supported manual triggers run from the editor." }, { status: started.alreadyStarted ? 200 : 202 });
|
|
4352
3930
|
}
|
|
4353
3931
|
if (url.pathname === `${CHAT_WEB_API_PREFIX}/signals/statuses` && request.method === "GET") {
|
|
4354
3932
|
await requireSession(request, context);
|
|
@@ -4524,6 +4102,7 @@ export function createChatWebApp(options = {}) {
|
|
|
4524
4102
|
});
|
|
4525
4103
|
return workflowValidationBlockedResponse("Workflow draft has validation errors and cannot be test-run", validation, { draft: serializeWorkflowDraft(record) });
|
|
4526
4104
|
}
|
|
4105
|
+
const room = body.roomId ? requireRoom(state, body.roomId, webSession, "write") : state.roomService.ensureDefaultRoom();
|
|
4527
4106
|
const result = await runWorkflowManualTextTrigger({
|
|
4528
4107
|
definition: record.definition,
|
|
4529
4108
|
triggerNodeId: body.triggerNodeId,
|
|
@@ -4532,11 +4111,31 @@ export function createChatWebApp(options = {}) {
|
|
|
4532
4111
|
draftId: record.draftId,
|
|
4533
4112
|
channelContext: context.channelContext,
|
|
4534
4113
|
channel: CHAT_WEB_CHANNEL,
|
|
4535
|
-
|
|
4114
|
+
roomId: room.id,
|
|
4115
|
+
defaultWorkspace: body.workspace ?? room.workspace ?? getDefaultPiboWorkspace(),
|
|
4536
4116
|
onSessionCreated: (session) => state.sessionQuery.upsertSession(session),
|
|
4537
4117
|
resolveProfile: (profileId) => resolveWorkflowRuntimeProfile({ context, requestedId: profileId }),
|
|
4538
4118
|
});
|
|
4539
4119
|
const diagnostics = result.ok ? validation.diagnostics : sanitizeWorkflowDiagnostics([...validation.diagnostics, ...result.diagnostics]);
|
|
4120
|
+
if (result.run) {
|
|
4121
|
+
const run = result.run;
|
|
4122
|
+
const store = state.workflowService.runtimeStore;
|
|
4123
|
+
store.transaction(() => {
|
|
4124
|
+
const hash = hashWorkflowDefinitionJson(record.definition);
|
|
4125
|
+
const existing = store.listDefinitionSnapshots({ workflowId: run.workflowId, workflowVersion: run.workflowVersion, hash, limit: 1 })[0];
|
|
4126
|
+
const definitionSnapshotId = existing?.id ?? `wfds_${run.id}`;
|
|
4127
|
+
if (!existing)
|
|
4128
|
+
store.saveDefinitionSnapshot({ id: definitionSnapshotId, workflowId: run.workflowId, workflowVersion: run.workflowVersion, hash, definition: record.definition, createdAt: run.createdAt });
|
|
4129
|
+
store.saveRun({ ...run, piboSessionId: result.nodeAttempts.find((attempt) => attempt.piboSessionId)?.piboSessionId, definitionSnapshotId, workflowDefinitionHash: hash, current: { status: run.status, nodeId: result.nodeAttempts.at(-1)?.nodeId }, state: { global: {} } });
|
|
4130
|
+
for (const attempt of result.nodeAttempts) {
|
|
4131
|
+
store.saveNodeAttempt({ ...attempt, attempt: 1 });
|
|
4132
|
+
if (attempt.piboSessionId)
|
|
4133
|
+
state.workflowService.addWorkflowSession({ piboSessionId: attempt.piboSessionId, workflowId: run.workflowId, workflowVersion: run.workflowVersion, workflowRunId: run.id, state: run.status });
|
|
4134
|
+
}
|
|
4135
|
+
for (const transfer of result.edgeTransfers)
|
|
4136
|
+
store.saveEdgeTransfer(transfer);
|
|
4137
|
+
});
|
|
4138
|
+
}
|
|
4540
4139
|
recordWorkflowLifecycleEvent(state, webSession, {
|
|
4541
4140
|
type: result.ok ? "workflow.editor_test_run.completed" : "workflow.editor_test_run.failed",
|
|
4542
4141
|
workflowId: record.workflowId,
|
|
@@ -4673,13 +4272,12 @@ export function createChatWebApp(options = {}) {
|
|
|
4673
4272
|
return responseJson(archiveWorkflowIdentity(state, context, webSession, archiveWorkflowId, body.reason));
|
|
4674
4273
|
}
|
|
4675
4274
|
if (url.pathname === `${CHAT_WEB_API_PREFIX}/workflows/lifecycle-events` && request.method === "GET") {
|
|
4676
|
-
|
|
4275
|
+
await requireSession(request, context);
|
|
4677
4276
|
return responseJson({
|
|
4678
4277
|
events: state.workflowLifecycleEventStore.listEvents({
|
|
4679
4278
|
type: url.searchParams.get("type") ?? undefined,
|
|
4680
4279
|
workflowId: url.searchParams.get("workflowId") ?? undefined,
|
|
4681
4280
|
draftId: url.searchParams.get("draftId") ?? undefined,
|
|
4682
|
-
projectId: url.searchParams.get("projectId") ?? undefined,
|
|
4683
4281
|
piboSessionId: url.searchParams.get("piboSessionId") ?? undefined,
|
|
4684
4282
|
workflowRunId: url.searchParams.get("workflowRunId") ?? undefined,
|
|
4685
4283
|
limit: parsePositiveIntSearchParam(url, "limit", 100, 500),
|
|
@@ -4991,12 +4589,42 @@ export function createChatWebApp(options = {}) {
|
|
|
4991
4589
|
sessions: await buildSessionNodes(ownedSessions, state.sessionQuery.listSessions(), process.cwd(), new Map(), sessionNodeHistoryOptions(context)),
|
|
4992
4590
|
});
|
|
4993
4591
|
}
|
|
4592
|
+
if (roomResource?.child === "order" && request.method === "PATCH") {
|
|
4593
|
+
requireSameOriginJsonRequest(request);
|
|
4594
|
+
const webSession = await requireSession(request, context);
|
|
4595
|
+
const room = requireRoom(state, roomResource.roomId, webSession, "admin");
|
|
4596
|
+
const body = await readJsonBody(request);
|
|
4597
|
+
if (typeof body.targetRoomId !== "string" || !body.targetRoomId) {
|
|
4598
|
+
throw new PiboWebHttpError("targetRoomId is required", 400);
|
|
4599
|
+
}
|
|
4600
|
+
if (body.position !== "before" && body.position !== "after") {
|
|
4601
|
+
throw new PiboWebHttpError("position must be before or after", 400);
|
|
4602
|
+
}
|
|
4603
|
+
const targetRoom = requireRoom(state, body.targetRoomId, webSession, "admin");
|
|
4604
|
+
return responseJson({
|
|
4605
|
+
orderedRoomIds: reorderChatWebRoom({ state, room, targetRoom, position: body.position }),
|
|
4606
|
+
});
|
|
4607
|
+
}
|
|
4994
4608
|
if (roomResource && roomResource.child === undefined && request.method === "PATCH") {
|
|
4995
4609
|
requireSameOriginJsonRequest(request);
|
|
4996
4610
|
const webSession = await requireSession(request, context);
|
|
4997
4611
|
const existingRoom = requireRoom(state, roomResource.roomId, webSession, "admin");
|
|
4998
4612
|
const body = await readJsonBody(request);
|
|
4613
|
+
if (body.pinned !== undefined && existingRoom.parentRoomId) {
|
|
4614
|
+
throw new PiboWebHttpError("Only top-level rooms can be pinned", 400);
|
|
4615
|
+
}
|
|
4616
|
+
if (body.pinned === true && (body.archived === true || isPiboRoomArchived(existingRoom))) {
|
|
4617
|
+
throw new PiboWebHttpError("Archived rooms cannot be pinned", 400);
|
|
4618
|
+
}
|
|
4999
4619
|
const update = createRoomUpdate(existingRoom, body);
|
|
4620
|
+
if (typeof body.pinned === "boolean") {
|
|
4621
|
+
const targetGroup = state.roomService.listRooms().filter((room) => !room.parentRoomId
|
|
4622
|
+
&& !isDefaultPiboRoom(room)
|
|
4623
|
+
&& !isPiboRoomArchived(room)
|
|
4624
|
+
&& room.id !== existingRoom.id
|
|
4625
|
+
&& isPiboRoomPinned(room) === body.pinned);
|
|
4626
|
+
update.metadata = withPiboRoomPinned(update.metadata ?? existingRoom.metadata, body.pinned, nextChatWebRoomSidebarOrder(targetGroup));
|
|
4627
|
+
}
|
|
5000
4628
|
if (update.parentRoomId)
|
|
5001
4629
|
requireRoom(state, update.parentRoomId, webSession, "admin");
|
|
5002
4630
|
let room;
|
|
@@ -5796,17 +5424,6 @@ export function createChatWebApp(options = {}) {
|
|
|
5796
5424
|
const selectedSession = resolveRequestedSession(state, context, webSession, defaultProfile, requestedPiboSessionId, requestedRoomId);
|
|
5797
5425
|
const cursor = parseSseCursor(url.searchParams.get("since")) ?? parseSseCursor(request.headers.get("last-event-id"));
|
|
5798
5426
|
const transientReplayCursor = parseTransientReplayCursor(url.searchParams.get("liveSince"));
|
|
5799
|
-
if (!requestedRoomId && state.projectService.getProjectSession(selectedSession.id)) {
|
|
5800
|
-
return createEventStream({
|
|
5801
|
-
piboSessionId: selectedSession.id,
|
|
5802
|
-
activePiboSessionId: selectedSession.id,
|
|
5803
|
-
mode: streamMode,
|
|
5804
|
-
context,
|
|
5805
|
-
state,
|
|
5806
|
-
cursor,
|
|
5807
|
-
transientReplayCursor,
|
|
5808
|
-
});
|
|
5809
|
-
}
|
|
5810
5427
|
const roomId = requestedRoomId ?? selectedRoomIdForSession(state, context, selectedSession);
|
|
5811
5428
|
requireRoom(state, roomId, webSession, "read");
|
|
5812
5429
|
const streamPiboSessionId = requestedPiboSessionId || !requestedRoomId ? selectedSession.id : undefined;
|