@pasko70/pibo 3.2.7 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-runtime/capabilities.js +5 -0
- package/dist/agent-runtime/contract.js +2 -0
- package/dist/agent-runtime/routed-session.js +68 -11
- package/dist/agent-runtimes/codex-native/adapter.js +4 -1
- package/dist/agent-runtimes/codex-native/process.js +1 -1
- package/dist/agent-runtimes/codex-native/protocol-version.js +6 -6
- package/dist/agent-runtimes/codex-native/thread.js +26 -4
- package/dist/agent-runtimes/omp/adapter.js +1 -0
- package/dist/agent-runtimes/omp/process.js +23 -3
- package/dist/agent-runtimes/omp/protocol-version.js +2 -0
- package/dist/agent-runtimes/pi/adapter.js +5 -1
- package/dist/agent-runtimes/pi/model-catalog.js +2 -2
- package/dist/agent-runtimes/pi/routed-session.js +53 -5
- package/dist/agent-runtimes/pi/runtime.js +6 -3
- package/dist/apps/chat/chat-api-routes.js +12 -38
- package/dist/apps/chat/chat-request-normalizers.js +15 -50
- 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/session-metadata.js +30 -0
- package/dist/apps/chat/trace.js +15 -2
- package/dist/apps/chat/types/rooms.js +30 -0
- package/dist/apps/chat/web-app.js +355 -651
- 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-ENXYFYda.js → dist-AhtdAETR.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CGgUuVB6.js → dist-Bk_L1qbJ.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DG6T1maU.js → dist-Dyp6sLQn.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CFtZTGHa.js → dist-jVaiGXFD.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BikaGikn.js → dist-t25moyJS.js} +1 -1
- package/dist/apps/chat-ui/assets/index-CZjNw-aK.js +228 -0
- package/dist/apps/chat-ui/assets/index-CcEjFITM.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-Spj6M0tn.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 +19 -10
- package/dist/debug/agents.js +9 -3
- package/dist/plugins/builtin.js +2 -0
- package/dist/plugins/registry.js +1 -0
- 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 +12 -2
- package/dist/providers/openai-gpt56.js +41 -3
- package/dist/sessions/workflow-session-kind.js +0 -3
- package/dist/subagents/context.js +2 -2
- package/dist/subagents/observation-query.js +49 -6
- package/dist/subagents/observation-text-regex.js +124 -0
- package/dist/subagents/tool.js +3 -2
- package/dist/tools/hashline.js +64 -0
- package/npm-shrinkwrap.json +786 -284
- package/package.json +11 -6
- 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-BwT5grLv.css +0 -1
- package/dist/apps/chat-ui/assets/index-PTJanD3E.js +0 -228
- package/dist/apps/chat-vscode-web/assets/index-D1bpAUkR.js +0 -43
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { SqliteWorkflowRunStore } from "../../../../packages/workflows/dist/index.js";
|
|
4
|
+
import { piboHomePath } from "../../../core/pibo-home.js";
|
|
5
|
+
export class ChatWorkflowSessionService {
|
|
6
|
+
path;
|
|
7
|
+
runtimeStore;
|
|
8
|
+
catalogDataStore;
|
|
9
|
+
constructor(path = piboHomePath("pibo-workflows.sqlite")) {
|
|
10
|
+
this.path = path === ":memory:" ? path : resolve(path);
|
|
11
|
+
this.runtimeStore = new SqliteWorkflowRunStore(this.path);
|
|
12
|
+
this.catalogDataStore = this.runtimeStore;
|
|
13
|
+
}
|
|
14
|
+
close() { this.runtimeStore.close(); }
|
|
15
|
+
getWorkflowSession(piboSessionId) {
|
|
16
|
+
const row = this.runtimeStore.db.prepare("SELECT * FROM workflow_session_links WHERE pibo_session_id = ?").get(piboSessionId);
|
|
17
|
+
if (!row) {
|
|
18
|
+
const run = this.runtimeStore.listRuns({ piboSessionId, limit: 1 })[0];
|
|
19
|
+
return run ? { piboSessionId, workflowId: run.workflowId, workflowVersion: run.workflowVersion, workflowRunId: run.id, state: run.status, createdAt: run.createdAt, updatedAt: run.updatedAt } : undefined;
|
|
20
|
+
}
|
|
21
|
+
const run = row.workflow_run_id ? this.runtimeStore.getRun(row.workflow_run_id) : undefined;
|
|
22
|
+
return workflowSessionFromRow(row, run?.status);
|
|
23
|
+
}
|
|
24
|
+
addWorkflowSession(input) {
|
|
25
|
+
if (input.state && !["configured", "pending", "running", "waiting", "completed", "failed", "cancelled"].includes(input.state))
|
|
26
|
+
throw new Error(`Unsupported Workflow session state '${input.state}'`);
|
|
27
|
+
const existing = this.getWorkflowSession(input.piboSessionId);
|
|
28
|
+
const workflowVersion = input.workflowVersion ?? existing?.workflowVersion;
|
|
29
|
+
const workflowRunId = input.workflowRunId ?? existing?.workflowRunId;
|
|
30
|
+
const configuration = input.configuration ?? existing?.configuration;
|
|
31
|
+
if (existing)
|
|
32
|
+
assertImmutableWorkflowSelection(existing, { ...input, workflowVersion, workflowRunId, configuration });
|
|
33
|
+
if (workflowRunId) {
|
|
34
|
+
const run = this.runtimeStore.getRun(workflowRunId);
|
|
35
|
+
if (run && (run.workflowId !== input.workflowId || run.workflowVersion !== workflowVersion)) {
|
|
36
|
+
throw new Error("Workflow run linkage conflicts with the workflow session");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const now = new Date().toISOString();
|
|
40
|
+
this.runtimeStore.db.prepare(`INSERT INTO workflow_session_links (
|
|
41
|
+
pibo_session_id, workflow_id, workflow_version, workflow_run_id, state, configuration_json, created_at, updated_at
|
|
42
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
43
|
+
ON CONFLICT(pibo_session_id) DO UPDATE SET
|
|
44
|
+
workflow_id = excluded.workflow_id,
|
|
45
|
+
workflow_version = excluded.workflow_version,
|
|
46
|
+
workflow_run_id = excluded.workflow_run_id,
|
|
47
|
+
state = excluded.state,
|
|
48
|
+
configuration_json = excluded.configuration_json,
|
|
49
|
+
updated_at = excluded.updated_at`).run(input.piboSessionId, input.workflowId, workflowVersion ?? null, workflowRunId ?? null, input.state ?? existing?.state ?? "configured", configuration ? JSON.stringify(configuration) : null, existing?.createdAt ?? now, now);
|
|
50
|
+
return this.getWorkflowSession(input.piboSessionId);
|
|
51
|
+
}
|
|
52
|
+
saveWorkflowSessionSnapshot(snapshot) {
|
|
53
|
+
return this.runtimeStore.transaction(() => {
|
|
54
|
+
const link = this.getWorkflowSession(snapshot.piboSessionId);
|
|
55
|
+
if (!link)
|
|
56
|
+
throw new Error("Workflow session not found");
|
|
57
|
+
if (link.workflowId !== snapshot.workflow.id || (link.workflowVersion && link.workflowVersion !== snapshot.workflow.version)) {
|
|
58
|
+
throw new Error("Workflow session snapshot does not match selected workflow");
|
|
59
|
+
}
|
|
60
|
+
const existing = this.getWorkflowSessionSnapshot(snapshot.id);
|
|
61
|
+
if (existing) {
|
|
62
|
+
if (canonicalJson(existing) !== canonicalJson(snapshot))
|
|
63
|
+
throw new Error("Workflow session snapshots are immutable");
|
|
64
|
+
return existing;
|
|
65
|
+
}
|
|
66
|
+
const existingForSession = this.getWorkflowSessionSnapshotForSession(snapshot.piboSessionId);
|
|
67
|
+
if (existingForSession)
|
|
68
|
+
throw new Error(`Workflow session '${snapshot.piboSessionId}' already has a configuration snapshot`);
|
|
69
|
+
const definitionSnapshot = this.runtimeStore.listDefinitionSnapshots({ workflowId: snapshot.workflow.id, workflowVersion: snapshot.workflow.version, hash: snapshot.workflow.effectiveDefinitionHash, limit: 1 })[0];
|
|
70
|
+
if (definitionSnapshot && canonicalJson(definitionSnapshot.definition) !== canonicalJson(snapshot.effectiveDefinition)) {
|
|
71
|
+
throw new Error("Executable Workflow definition snapshot conflicts with the session snapshot");
|
|
72
|
+
}
|
|
73
|
+
if (!definitionSnapshot)
|
|
74
|
+
this.runtimeStore.saveDefinitionSnapshot({
|
|
75
|
+
id: snapshot.id,
|
|
76
|
+
workflowId: snapshot.workflow.id,
|
|
77
|
+
workflowVersion: snapshot.workflow.version,
|
|
78
|
+
hash: snapshot.workflow.effectiveDefinitionHash,
|
|
79
|
+
definition: snapshot.effectiveDefinition,
|
|
80
|
+
createdAt: snapshot.createdAt,
|
|
81
|
+
});
|
|
82
|
+
this.runtimeStore.db.prepare(`INSERT INTO workflow_session_snapshots (
|
|
83
|
+
id, pibo_session_id, workflow_id, workflow_version, base_definition_hash, effective_definition_hash, snapshot_json, created_at
|
|
84
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(snapshot.id, snapshot.piboSessionId, snapshot.workflow.id, snapshot.workflow.version, snapshot.workflow.baseDefinitionHash, snapshot.workflow.effectiveDefinitionHash, JSON.stringify(snapshot), snapshot.createdAt);
|
|
85
|
+
return snapshot;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
getWorkflowSessionSnapshot(id) {
|
|
89
|
+
const row = this.runtimeStore.db.prepare("SELECT * FROM workflow_session_snapshots WHERE id = ?").get(id);
|
|
90
|
+
return row ? workflowSessionSnapshotFromRow(row) : undefined;
|
|
91
|
+
}
|
|
92
|
+
getWorkflowSessionSnapshotForSession(piboSessionId) {
|
|
93
|
+
const row = this.runtimeStore.db.prepare("SELECT * FROM workflow_session_snapshots WHERE pibo_session_id = ?").get(piboSessionId);
|
|
94
|
+
return row ? workflowSessionSnapshotFromRow(row) : undefined;
|
|
95
|
+
}
|
|
96
|
+
startWorkflowSessionRun(input) {
|
|
97
|
+
return this.runtimeStore.transaction(() => {
|
|
98
|
+
const link = this.getWorkflowSession(input.piboSessionId);
|
|
99
|
+
if (!link)
|
|
100
|
+
throw new Error("Workflow session not found");
|
|
101
|
+
if (link.workflowId !== input.workflowId || link.workflowVersion !== input.workflowVersion)
|
|
102
|
+
throw new Error("Workflow session selection is immutable");
|
|
103
|
+
const snapshot = this.getWorkflowSessionSnapshot(input.snapshotId);
|
|
104
|
+
if (!snapshot || snapshot.piboSessionId !== input.piboSessionId)
|
|
105
|
+
throw new Error("Workflow session snapshot not found");
|
|
106
|
+
if (snapshot.workflow.id !== input.workflowId || snapshot.workflow.version !== input.workflowVersion || snapshot.workflow.effectiveDefinitionHash !== input.effectiveDefinitionHash) {
|
|
107
|
+
throw new Error("Workflow session snapshot does not match selected workflow");
|
|
108
|
+
}
|
|
109
|
+
if (link.workflowRunId) {
|
|
110
|
+
const existingRun = this.getWorkflowRun(link.workflowRunId);
|
|
111
|
+
if (!existingRun)
|
|
112
|
+
throw new Error("Workflow session references a missing Workflow run");
|
|
113
|
+
return { workflowSession: this.getWorkflowSession(input.piboSessionId), run: existingRun, alreadyStarted: true };
|
|
114
|
+
}
|
|
115
|
+
if (this.runtimeStore.getRun(input.runId))
|
|
116
|
+
throw new Error(`Workflow run '${input.runId}' already exists`);
|
|
117
|
+
const definitionSnapshot = this.runtimeStore.listDefinitionSnapshots({ workflowId: input.workflowId, workflowVersion: input.workflowVersion, hash: input.effectiveDefinitionHash, limit: 1 })[0];
|
|
118
|
+
if (!definitionSnapshot)
|
|
119
|
+
throw new Error("Executable Workflow definition snapshot not found");
|
|
120
|
+
const now = new Date().toISOString();
|
|
121
|
+
const run = {
|
|
122
|
+
id: input.runId,
|
|
123
|
+
workflowId: input.workflowId,
|
|
124
|
+
workflowVersion: input.workflowVersion,
|
|
125
|
+
workflowDefinitionHash: input.effectiveDefinitionHash,
|
|
126
|
+
definitionSnapshotId: definitionSnapshot.id,
|
|
127
|
+
piboSessionId: input.piboSessionId,
|
|
128
|
+
status: "pending",
|
|
129
|
+
current: input.current,
|
|
130
|
+
input: input.inputValues,
|
|
131
|
+
state: { global: {} },
|
|
132
|
+
...(input.validation ? { validation: input.validation } : {}),
|
|
133
|
+
createdAt: now,
|
|
134
|
+
updatedAt: now,
|
|
135
|
+
};
|
|
136
|
+
this.runtimeStore.saveRun(run);
|
|
137
|
+
this.runtimeStore.db.prepare("UPDATE workflow_session_links SET workflow_run_id = ?, state = 'pending', updated_at = ? WHERE pibo_session_id = ? AND workflow_run_id IS NULL")
|
|
138
|
+
.run(run.id, now, input.piboSessionId);
|
|
139
|
+
return { workflowSession: this.getWorkflowSession(input.piboSessionId), run: workflowRunToPublic(run, snapshot.id), alreadyStarted: false };
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
getWorkflowRun(runId) {
|
|
143
|
+
const run = this.runtimeStore.getRun(runId);
|
|
144
|
+
return run ? workflowRunToPublic(run, run.piboSessionId ? this.getWorkflowSessionSnapshotForSession(run.piboSessionId)?.id : undefined) : undefined;
|
|
145
|
+
}
|
|
146
|
+
getWorkflowRunForSession(piboSessionId) {
|
|
147
|
+
const link = this.getWorkflowSession(piboSessionId);
|
|
148
|
+
if (link?.workflowRunId)
|
|
149
|
+
return this.getWorkflowRun(link.workflowRunId);
|
|
150
|
+
const runs = this.runtimeStore.listRuns({ piboSessionId, limit: 2 });
|
|
151
|
+
if (runs.length > 1)
|
|
152
|
+
throw new Error(`Workflow session '${piboSessionId}' has multiple root runs`);
|
|
153
|
+
return runs[0] ? this.getWorkflowRun(runs[0].id) : undefined;
|
|
154
|
+
}
|
|
155
|
+
listWorkflowRuns(filter = {}) {
|
|
156
|
+
if (filter.piboSessionId) {
|
|
157
|
+
const run = this.getWorkflowRunForSession(filter.piboSessionId);
|
|
158
|
+
return run && (!filter.workflowId || run.workflowId === filter.workflowId) && (!filter.status || run.status === filter.status) ? [run] : [];
|
|
159
|
+
}
|
|
160
|
+
return this.runtimeStore.listRuns(filter).map((run) => this.getWorkflowRun(run.id));
|
|
161
|
+
}
|
|
162
|
+
saveWorkflowWaitToken(token) {
|
|
163
|
+
return this.runtimeStore.transaction(() => {
|
|
164
|
+
this.assertRunSession(token.workflowRunId, token.piboSessionId);
|
|
165
|
+
this.runtimeStore.saveWaitToken(publicWaitTokenToRuntime(token));
|
|
166
|
+
if (token.status === "pending")
|
|
167
|
+
this.updateRunAndRootLinkState(token.workflowRunId, "waiting", token.createdAt);
|
|
168
|
+
return this.getWorkflowWaitToken(token.id);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
getWorkflowWaitToken(waitTokenId) {
|
|
172
|
+
const token = this.runtimeStore.getWaitToken(waitTokenId);
|
|
173
|
+
if (!token)
|
|
174
|
+
return undefined;
|
|
175
|
+
return this.runtimeWaitTokenToPublic(token);
|
|
176
|
+
}
|
|
177
|
+
listWorkflowWaitTokens(filter = {}) {
|
|
178
|
+
let workflowRunId = filter.workflowRunId;
|
|
179
|
+
if (filter.piboSessionId) {
|
|
180
|
+
const run = this.getWorkflowRunForSession(filter.piboSessionId);
|
|
181
|
+
if (!run)
|
|
182
|
+
return [];
|
|
183
|
+
if (workflowRunId && workflowRunId !== run.id)
|
|
184
|
+
return [];
|
|
185
|
+
workflowRunId = run.id;
|
|
186
|
+
}
|
|
187
|
+
return this.runtimeStore.listWaitTokens({ workflowRunId, status: filter.status, limit: filter.limit }).map((token) => this.runtimeWaitTokenToPublic(token));
|
|
188
|
+
}
|
|
189
|
+
expireWorkflowWaitToken(input) {
|
|
190
|
+
return this.runtimeStore.transaction(() => {
|
|
191
|
+
this.assertRunSession(input.workflowRunId, input.piboSessionId);
|
|
192
|
+
const token = this.runtimeStore.getWaitToken(input.waitTokenId);
|
|
193
|
+
if (!token || token.workflowRunId !== input.workflowRunId)
|
|
194
|
+
throw new Error("Workflow wait token not found for this Workflow session");
|
|
195
|
+
if (token.status !== "pending")
|
|
196
|
+
throw new Error(`Workflow wait token is ${token.status} and cannot be expired again`);
|
|
197
|
+
const resolvedAt = input.resolvedAt ?? new Date().toISOString();
|
|
198
|
+
if (!Number.isFinite(Date.parse(resolvedAt)))
|
|
199
|
+
throw new Error("Workflow wait token expiry resolution time is invalid");
|
|
200
|
+
if (!token.expiresAt || Date.parse(token.expiresAt) > Date.parse(resolvedAt))
|
|
201
|
+
throw new Error("Workflow wait token has not expired");
|
|
202
|
+
for (const pending of this.runtimeStore.listWaitTokens({ workflowRunId: input.workflowRunId, status: "pending", limit: 500 })) {
|
|
203
|
+
if (pending.expiresAt && Date.parse(pending.expiresAt) <= Date.parse(resolvedAt))
|
|
204
|
+
this.runtimeStore.saveWaitToken({ ...pending, status: "expired", resumedAt: resolvedAt });
|
|
205
|
+
}
|
|
206
|
+
const stillPending = this.runtimeStore.listWaitTokens({ workflowRunId: input.workflowRunId, status: "pending", limit: 1 }).length > 0;
|
|
207
|
+
this.updateRunAndRootLinkState(input.workflowRunId, stillPending ? "waiting" : "failed", resolvedAt);
|
|
208
|
+
return { waitToken: this.getWorkflowWaitToken(input.waitTokenId), run: this.getWorkflowRun(input.workflowRunId), workflowSession: this.getWorkflowSession(input.piboSessionId) };
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
resolveWorkflowHumanAction(input) {
|
|
212
|
+
const actedAt = input.actedAt ?? new Date().toISOString();
|
|
213
|
+
const tokenBefore = this.runtimeStore.getWaitToken(input.waitTokenId);
|
|
214
|
+
if (tokenBefore?.expiresAt && tokenBefore.status === "pending" && Date.parse(tokenBefore.expiresAt) <= Date.parse(actedAt)) {
|
|
215
|
+
this.expireWorkflowWaitToken({ ...input, resolvedAt: actedAt });
|
|
216
|
+
throw new Error(`Workflow wait token expired at ${tokenBefore.expiresAt}`);
|
|
217
|
+
}
|
|
218
|
+
return this.runtimeStore.transaction(() => {
|
|
219
|
+
this.assertRunSession(input.workflowRunId, input.piboSessionId);
|
|
220
|
+
const token = this.runtimeStore.getWaitToken(input.waitTokenId);
|
|
221
|
+
if (!token || token.workflowRunId !== input.workflowRunId)
|
|
222
|
+
throw new Error("Workflow wait token not found for this Workflow session");
|
|
223
|
+
if (token.status !== "pending")
|
|
224
|
+
throw new Error(`Workflow wait token is ${token.status} and cannot be resolved again`);
|
|
225
|
+
const actionRef = input.actionId ? token.actions.find((action) => action.id === input.actionId) : token.actions.find((action) => action.kind === input.kind);
|
|
226
|
+
if (!actionRef)
|
|
227
|
+
throw new Error("Workflow wait token does not offer the requested human action");
|
|
228
|
+
if (actionRef.kind && actionRef.kind !== input.kind)
|
|
229
|
+
throw new Error("Workflow wait token action kind does not match the requested kind");
|
|
230
|
+
const action = {
|
|
231
|
+
id: input.actionRecordId ?? `wha_${randomUUID()}`,
|
|
232
|
+
workflowRunId: input.workflowRunId,
|
|
233
|
+
waitTokenId: input.waitTokenId,
|
|
234
|
+
actionId: actionRef.id,
|
|
235
|
+
kind: input.kind,
|
|
236
|
+
...(input.actor ? { actor: input.actor } : {}),
|
|
237
|
+
...(input.payload !== undefined ? { payload: input.payload } : {}),
|
|
238
|
+
createdAt: actedAt,
|
|
239
|
+
};
|
|
240
|
+
if (this.runtimeStore.getHumanAction(action.id))
|
|
241
|
+
throw new Error(`Workflow human action '${action.id}' already exists`);
|
|
242
|
+
this.runtimeStore.saveHumanAction(action);
|
|
243
|
+
const cancelled = input.kind === "cancel";
|
|
244
|
+
this.runtimeStore.saveWaitToken({ ...token, status: cancelled ? "cancelled" : "resumed", ...(input.payload !== undefined ? { resumePayload: input.payload } : {}), resumedAt: actedAt });
|
|
245
|
+
this.updateRunAndRootLinkState(input.workflowRunId, cancelled ? "cancelled" : "running", actedAt);
|
|
246
|
+
return {
|
|
247
|
+
waitToken: this.getWorkflowWaitToken(input.waitTokenId),
|
|
248
|
+
action: this.runtimeHumanActionToPublic(action),
|
|
249
|
+
run: this.getWorkflowRun(input.workflowRunId),
|
|
250
|
+
workflowSession: this.getWorkflowSession(input.piboSessionId),
|
|
251
|
+
};
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
listWorkflowHumanActions(filter = {}) {
|
|
255
|
+
let workflowRunId = filter.workflowRunId;
|
|
256
|
+
if (filter.piboSessionId) {
|
|
257
|
+
const run = this.getWorkflowRunForSession(filter.piboSessionId);
|
|
258
|
+
if (!run)
|
|
259
|
+
return [];
|
|
260
|
+
if (workflowRunId && workflowRunId !== run.id)
|
|
261
|
+
return [];
|
|
262
|
+
workflowRunId = run.id;
|
|
263
|
+
}
|
|
264
|
+
return this.runtimeStore.listHumanActions({ workflowRunId, waitTokenId: filter.waitTokenId, limit: filter.limit }).map((action) => this.runtimeHumanActionToPublic(action));
|
|
265
|
+
}
|
|
266
|
+
assertRunSession(workflowRunId, piboSessionId) {
|
|
267
|
+
const run = this.runtimeStore.getRun(workflowRunId);
|
|
268
|
+
if (!run || (run.piboSessionId !== piboSessionId && this.getWorkflowSession(piboSessionId)?.workflowRunId !== workflowRunId))
|
|
269
|
+
throw new Error("Workflow run does not belong to this Workflow session");
|
|
270
|
+
return run;
|
|
271
|
+
}
|
|
272
|
+
updateRunAndRootLinkState(workflowRunId, status, at) {
|
|
273
|
+
const run = this.runtimeStore.getRun(workflowRunId);
|
|
274
|
+
if (!run)
|
|
275
|
+
throw new Error("Workflow run not found");
|
|
276
|
+
this.runtimeStore.saveRun({
|
|
277
|
+
...run,
|
|
278
|
+
status,
|
|
279
|
+
current: { ...run.current, status },
|
|
280
|
+
updatedAt: at,
|
|
281
|
+
...(status === "failed" ? { failedAt: run.failedAt ?? at } : {}),
|
|
282
|
+
...(status === "cancelled" ? { cancelledAt: run.cancelledAt ?? at } : {}),
|
|
283
|
+
...(status === "completed" ? { completedAt: run.completedAt ?? at } : {}),
|
|
284
|
+
});
|
|
285
|
+
this.runtimeStore.db.prepare("UPDATE workflow_session_links SET state = ?, updated_at = ? WHERE workflow_run_id = ?").run(status, at, workflowRunId);
|
|
286
|
+
}
|
|
287
|
+
runtimeWaitTokenToPublic(token) {
|
|
288
|
+
const run = this.runtimeStore.getRun(token.workflowRunId);
|
|
289
|
+
if (!run?.piboSessionId)
|
|
290
|
+
throw new Error(`Workflow wait token '${token.id}' references a missing session-linked run`);
|
|
291
|
+
return {
|
|
292
|
+
id: token.id, piboSessionId: run.piboSessionId, workflowRunId: token.workflowRunId,
|
|
293
|
+
...(token.nodeAttemptId ? { nodeAttemptId: token.nodeAttemptId } : {}),
|
|
294
|
+
...(token.humanNodeId ? { humanNodeId: token.humanNodeId } : {}),
|
|
295
|
+
actions: token.actions, prompt: token.prompt,
|
|
296
|
+
...(token.schema ? { schema: token.schema } : {}), status: token.status,
|
|
297
|
+
...(token.resumePayload !== undefined ? { resumePayload: token.resumePayload } : {}),
|
|
298
|
+
createdAt: token.createdAt, ...(token.expiresAt ? { expiresAt: token.expiresAt } : {}),
|
|
299
|
+
...(token.resumedAt ? { resolvedAt: token.resumedAt } : {}),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
runtimeHumanActionToPublic(action) {
|
|
303
|
+
const run = this.runtimeStore.getRun(action.workflowRunId);
|
|
304
|
+
if (!run?.piboSessionId)
|
|
305
|
+
throw new Error(`Workflow human action '${action.id}' references a missing session-linked run`);
|
|
306
|
+
return { id: action.id, piboSessionId: run.piboSessionId, workflowRunId: action.workflowRunId, waitTokenId: action.waitTokenId,
|
|
307
|
+
...(action.actionId ? { actionId: action.actionId } : {}), kind: action.kind,
|
|
308
|
+
...(action.actor ? { actor: action.actor } : {}), ...(action.payload !== undefined ? { payload: action.payload } : {}), createdAt: action.createdAt };
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function workflowSessionFromRow(row, runStatus) {
|
|
312
|
+
const configuration = row.configuration_json ? parseJsonObject(row.configuration_json) : undefined;
|
|
313
|
+
return { piboSessionId: row.pibo_session_id, workflowId: row.workflow_id,
|
|
314
|
+
...(row.workflow_version ? { workflowVersion: row.workflow_version } : {}), ...(row.workflow_run_id ? { workflowRunId: row.workflow_run_id } : {}),
|
|
315
|
+
state: normalizePublicRunStatus(runStatus) ?? row.state, ...(configuration ? { configuration } : {}), createdAt: row.created_at, updatedAt: row.updated_at };
|
|
316
|
+
}
|
|
317
|
+
function workflowSessionSnapshotFromRow(row) {
|
|
318
|
+
const parsed = JSON.parse(row.snapshot_json);
|
|
319
|
+
if (!parsed || typeof parsed !== "object" || parsed.id !== row.id || parsed.piboSessionId !== row.pibo_session_id || parsed.workflow?.id !== row.workflow_id || parsed.workflow.version !== row.workflow_version || parsed.workflow.baseDefinitionHash !== row.base_definition_hash || parsed.workflow.effectiveDefinitionHash !== row.effective_definition_hash) {
|
|
320
|
+
throw new Error(`Malformed Workflow session snapshot '${row.id}'`);
|
|
321
|
+
}
|
|
322
|
+
return parsed;
|
|
323
|
+
}
|
|
324
|
+
function workflowRunToPublic(run, sessionSnapshotId) {
|
|
325
|
+
return { ...run, id: run.id, piboSessionId: run.piboSessionId, workflowId: run.workflowId, workflowVersion: run.workflowVersion,
|
|
326
|
+
snapshotId: sessionSnapshotId, definitionSnapshotId: run.definitionSnapshotId, effectiveDefinitionHash: run.workflowDefinitionHash, status: run.status,
|
|
327
|
+
current: run.current, input: run.input, ...(run.output !== undefined ? { output: run.output } : {}),
|
|
328
|
+
inputValues: run.input && typeof run.input === "object" && !Array.isArray(run.input) ? run.input : {},
|
|
329
|
+
...(run.validation ? { validation: run.validation } : {}), createdAt: run.createdAt, updatedAt: run.updatedAt,
|
|
330
|
+
...(run.completedAt ? { completedAt: run.completedAt } : {}), ...(run.failedAt ? { failedAt: run.failedAt } : {}), ...(run.cancelledAt ? { cancelledAt: run.cancelledAt } : {}) };
|
|
331
|
+
}
|
|
332
|
+
function publicWaitTokenToRuntime(token) {
|
|
333
|
+
return { id: token.id, workflowRunId: token.workflowRunId, ...(token.nodeAttemptId ? { nodeAttemptId: token.nodeAttemptId } : {}),
|
|
334
|
+
...(token.humanNodeId ? { humanNodeId: token.humanNodeId } : {}), actions: token.actions, prompt: token.prompt,
|
|
335
|
+
...(token.schema ? { schema: token.schema } : {}), status: token.status,
|
|
336
|
+
...(token.resumePayload !== undefined ? { resumePayload: token.resumePayload } : {}), createdAt: token.createdAt,
|
|
337
|
+
...(token.expiresAt ? { expiresAt: token.expiresAt } : {}), ...(token.resolvedAt ? { resumedAt: token.resolvedAt } : {}) };
|
|
338
|
+
}
|
|
339
|
+
function assertImmutableWorkflowSelection(existing, next) {
|
|
340
|
+
if (existing.workflowId !== next.workflowId || existing.workflowVersion !== next.workflowVersion)
|
|
341
|
+
throw new Error("Workflow session selection is immutable");
|
|
342
|
+
if (existing.workflowRunId && next.workflowRunId && existing.workflowRunId !== next.workflowRunId)
|
|
343
|
+
throw new Error("Workflow session run id is immutable");
|
|
344
|
+
if (canonicalJson(existing.configuration) !== canonicalJson(next.configuration))
|
|
345
|
+
throw new Error("Workflow session configuration is immutable");
|
|
346
|
+
}
|
|
347
|
+
function normalizePublicRunStatus(status) {
|
|
348
|
+
return status === "pending" || status === "running" || status === "waiting" || status === "completed" || status === "failed" || status === "cancelled" ? status : undefined;
|
|
349
|
+
}
|
|
350
|
+
function canonicalJson(value) { return JSON.stringify(value ?? null); }
|
|
351
|
+
function parseJsonObject(value) { const parsed = JSON.parse(value); if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
352
|
+
throw new Error("Malformed Workflow JSON object"); return parsed; }
|
package/dist/apps/chat/rooms.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { CHAT_ROOM_ID_METADATA_KEY, chatRoomIdFromMetadata, isDefaultPiboRoom, isPiboRoomArchived, roomWorkspaceFromMetadata, withChatRoomId, withPiboRoomArchived, withPiboRoomWorkspace, } from "./types/rooms.js";
|
|
1
|
+
export { CHAT_ROOM_ID_METADATA_KEY, chatRoomIdFromMetadata, comparePiboRoomsBySidebarOrder, isDefaultPiboRoom, isPiboRoomArchived, isPiboRoomPinned, piboRoomSidebarOrder, roomWorkspaceFromMetadata, withChatRoomId, withPiboRoomArchived, withPiboRoomPinned, withPiboRoomSidebarOrder, withPiboRoomWorkspace, } from "./types/rooms.js";
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
const CHAT_WEB_ARCHIVED_AT_KEY = "chatWebArchivedAt";
|
|
2
|
+
const CHAT_WEB_PINNED_AT_KEY = "chatWebPinnedAt";
|
|
3
|
+
const CHAT_WEB_SIDEBAR_ORDER_KEY = "chatWebSidebarOrder";
|
|
2
4
|
export function isChatWebSessionArchived(session) {
|
|
3
5
|
return typeof session.metadata?.[CHAT_WEB_ARCHIVED_AT_KEY] === "string";
|
|
4
6
|
}
|
|
7
|
+
export function isChatWebSessionPinned(session) {
|
|
8
|
+
return typeof session.metadata?.[CHAT_WEB_PINNED_AT_KEY] === "string";
|
|
9
|
+
}
|
|
10
|
+
export function chatWebSessionSidebarOrder(session) {
|
|
11
|
+
const value = session.metadata?.[CHAT_WEB_SIDEBAR_ORDER_KEY];
|
|
12
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
export function compareChatWebSessionsBySidebarOrder(left, right) {
|
|
15
|
+
const pinnedDifference = Number(isChatWebSessionPinned(right)) - Number(isChatWebSessionPinned(left));
|
|
16
|
+
if (pinnedDifference !== 0)
|
|
17
|
+
return pinnedDifference;
|
|
18
|
+
const leftOrder = chatWebSessionSidebarOrder(left) ?? (Date.parse(left.createdAt) || 0);
|
|
19
|
+
const rightOrder = chatWebSessionSidebarOrder(right) ?? (Date.parse(right.createdAt) || 0);
|
|
20
|
+
if (leftOrder !== rightOrder)
|
|
21
|
+
return rightOrder - leftOrder;
|
|
22
|
+
return right.id.localeCompare(left.id);
|
|
23
|
+
}
|
|
5
24
|
export function withChatWebArchived(metadata, archived) {
|
|
6
25
|
const next = { ...(metadata ?? {}) };
|
|
7
26
|
if (archived) {
|
|
@@ -12,3 +31,14 @@ export function withChatWebArchived(metadata, archived) {
|
|
|
12
31
|
}
|
|
13
32
|
return next;
|
|
14
33
|
}
|
|
34
|
+
export function withChatWebSessionPinned(metadata, pinned, order = Date.now()) {
|
|
35
|
+
const next = { ...(metadata ?? {}), [CHAT_WEB_SIDEBAR_ORDER_KEY]: order };
|
|
36
|
+
if (pinned)
|
|
37
|
+
next[CHAT_WEB_PINNED_AT_KEY] = new Date().toISOString();
|
|
38
|
+
else
|
|
39
|
+
delete next[CHAT_WEB_PINNED_AT_KEY];
|
|
40
|
+
return next;
|
|
41
|
+
}
|
|
42
|
+
export function withChatWebSessionSidebarOrder(metadata, order) {
|
|
43
|
+
return { ...(metadata ?? {}), [CHAT_WEB_SIDEBAR_ORDER_KEY]: order };
|
|
44
|
+
}
|
package/dist/apps/chat/trace.js
CHANGED
|
@@ -3,7 +3,7 @@ import { PI_HISTORY_PAGE_MAX_BYTES, PI_HISTORY_SCAN_MAX_BYTES, PI_HISTORY_TAIL_M
|
|
|
3
3
|
import { isPiboThinkingLevel } from "../../core/thinking.js";
|
|
4
4
|
import { isBuiltInHistoryReconciliationProof } from "../../agent-runtimes/history-proof.js";
|
|
5
5
|
import { buildTraceViewFromEvents, traceNodesFromHistoryEntries } from "../../shared/trace-engine.js";
|
|
6
|
-
import { isChatWebSessionArchived } from "./session-metadata.js";
|
|
6
|
+
import { chatWebSessionSidebarOrder, isChatWebSessionArchived, isChatWebSessionPinned } from "./session-metadata.js";
|
|
7
7
|
import { workflowSessionKindFromMetadata } from "../../sessions/workflow-session-kind.js";
|
|
8
8
|
export const TRACE_PROJECTION_VERSION = "runtime-history-v2-incomplete-status";
|
|
9
9
|
export { compareTraceNodes, sortTraceNodes, nestTraceNodes, flattenTraceNodes, mapTraceNodesById, buildTraceViewFromEvents, traceNodesFromHistoryEntries, } from "../../shared/trace-engine.js";
|
|
@@ -34,7 +34,10 @@ export async function buildSessionNodes(sessions, indexItems, _cwd = process.cwd
|
|
|
34
34
|
workflowSessionKind: workflowSessionKindFromMetadata(session.metadata),
|
|
35
35
|
title: createSessionTitle(session, historyMetadataFromInspection(inspection)),
|
|
36
36
|
subtitle: session.id,
|
|
37
|
+
createdAt: session.createdAt,
|
|
37
38
|
archived: isChatWebSessionArchived(session),
|
|
39
|
+
pinned: isChatWebSessionPinned(session),
|
|
40
|
+
sidebarOrder: chatWebSessionSidebarOrder(session),
|
|
38
41
|
status: sessionNodeStatus(indexed?.status),
|
|
39
42
|
lastActivityAt: indexed?.lastActivityAt ?? indexed?.createdAt ?? session.createdAt,
|
|
40
43
|
unreadCount: unreadCounts.get(session.id) || undefined,
|
|
@@ -70,7 +73,7 @@ export async function buildSessionNodes(sessions, indexItems, _cwd = process.cwd
|
|
|
70
73
|
});
|
|
71
74
|
}
|
|
72
75
|
const sortNodes = (items) => {
|
|
73
|
-
items.sort(
|
|
76
|
+
items.sort(compareSessionNodesBySidebarOrder);
|
|
74
77
|
for (const item of items) {
|
|
75
78
|
item.derivedSessions.sort((left, right) => (right.lastActivityAt ?? "").localeCompare(left.lastActivityAt ?? ""));
|
|
76
79
|
sortNodes(item.children);
|
|
@@ -79,6 +82,16 @@ export async function buildSessionNodes(sessions, indexItems, _cwd = process.cwd
|
|
|
79
82
|
sortNodes(roots);
|
|
80
83
|
return roots;
|
|
81
84
|
}
|
|
85
|
+
function compareSessionNodesBySidebarOrder(left, right) {
|
|
86
|
+
const pinnedDifference = Number(Boolean(right.pinned)) - Number(Boolean(left.pinned));
|
|
87
|
+
if (pinnedDifference !== 0)
|
|
88
|
+
return pinnedDifference;
|
|
89
|
+
const leftOrder = left.sidebarOrder ?? (Date.parse(left.createdAt ?? "") || 0);
|
|
90
|
+
const rightOrder = right.sidebarOrder ?? (Date.parse(right.createdAt ?? "") || 0);
|
|
91
|
+
if (leftOrder !== rightOrder)
|
|
92
|
+
return rightOrder - leftOrder;
|
|
93
|
+
return right.piboSessionId.localeCompare(left.piboSessionId);
|
|
94
|
+
}
|
|
82
95
|
function sessionNodeStatus(indexedStatus) {
|
|
83
96
|
return indexedStatus ?? "idle";
|
|
84
97
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export const CHAT_ROOM_ID_METADATA_KEY = "chatRoomId";
|
|
2
2
|
const CHAT_ROOM_ARCHIVED_AT_METADATA_KEY = "chatRoomArchivedAt";
|
|
3
|
+
const CHAT_ROOM_PINNED_AT_METADATA_KEY = "chatRoomPinnedAt";
|
|
4
|
+
const CHAT_ROOM_SIDEBAR_ORDER_METADATA_KEY = "chatRoomSidebarOrder";
|
|
3
5
|
const CHAT_ROOM_WORKSPACE_METADATA_KEY = "workspace";
|
|
4
6
|
export function chatRoomIdFromMetadata(metadata) {
|
|
5
7
|
const value = metadata?.[CHAT_ROOM_ID_METADATA_KEY];
|
|
@@ -14,6 +16,23 @@ export function isDefaultPiboRoom(room) {
|
|
|
14
16
|
export function isPiboRoomArchived(room) {
|
|
15
17
|
return typeof room.metadata[CHAT_ROOM_ARCHIVED_AT_METADATA_KEY] === "string";
|
|
16
18
|
}
|
|
19
|
+
export function isPiboRoomPinned(room) {
|
|
20
|
+
return typeof room.metadata[CHAT_ROOM_PINNED_AT_METADATA_KEY] === "string";
|
|
21
|
+
}
|
|
22
|
+
export function piboRoomSidebarOrder(room) {
|
|
23
|
+
const value = room.metadata[CHAT_ROOM_SIDEBAR_ORDER_METADATA_KEY];
|
|
24
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
25
|
+
}
|
|
26
|
+
export function comparePiboRoomsBySidebarOrder(left, right) {
|
|
27
|
+
const pinnedDifference = Number(isPiboRoomPinned(right)) - Number(isPiboRoomPinned(left));
|
|
28
|
+
if (pinnedDifference !== 0)
|
|
29
|
+
return pinnedDifference;
|
|
30
|
+
const leftOrder = piboRoomSidebarOrder(left) ?? (Date.parse(left.createdAt) || 0);
|
|
31
|
+
const rightOrder = piboRoomSidebarOrder(right) ?? (Date.parse(right.createdAt) || 0);
|
|
32
|
+
if (leftOrder !== rightOrder)
|
|
33
|
+
return rightOrder - leftOrder;
|
|
34
|
+
return right.id.localeCompare(left.id);
|
|
35
|
+
}
|
|
17
36
|
export function roomWorkspaceFromMetadata(metadata) {
|
|
18
37
|
const value = metadata?.[CHAT_ROOM_WORKSPACE_METADATA_KEY];
|
|
19
38
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
@@ -26,6 +45,17 @@ export function withPiboRoomArchived(metadata, archived) {
|
|
|
26
45
|
delete next[CHAT_ROOM_ARCHIVED_AT_METADATA_KEY];
|
|
27
46
|
return next;
|
|
28
47
|
}
|
|
48
|
+
export function withPiboRoomPinned(metadata, pinned, order = Date.now()) {
|
|
49
|
+
const next = { ...(metadata ?? {}), [CHAT_ROOM_SIDEBAR_ORDER_METADATA_KEY]: order };
|
|
50
|
+
if (pinned)
|
|
51
|
+
next[CHAT_ROOM_PINNED_AT_METADATA_KEY] = new Date().toISOString();
|
|
52
|
+
else
|
|
53
|
+
delete next[CHAT_ROOM_PINNED_AT_METADATA_KEY];
|
|
54
|
+
return next;
|
|
55
|
+
}
|
|
56
|
+
export function withPiboRoomSidebarOrder(metadata, order) {
|
|
57
|
+
return { ...(metadata ?? {}), [CHAT_ROOM_SIDEBAR_ORDER_METADATA_KEY]: order };
|
|
58
|
+
}
|
|
29
59
|
export function withPiboRoomWorkspace(metadata, workspace) {
|
|
30
60
|
const next = { ...(metadata ?? {}) };
|
|
31
61
|
if (workspace)
|