@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
|
@@ -6,6 +6,7 @@ const BOOLEAN_CAPABILITY_PATHS = [
|
|
|
6
6
|
"lifecycle.attach",
|
|
7
7
|
"lifecycle.listNativeSessions",
|
|
8
8
|
"lifecycle.fork",
|
|
9
|
+
"lifecycle.forkWhileRunning",
|
|
9
10
|
"lifecycle.clone",
|
|
10
11
|
"lifecycle.tree",
|
|
11
12
|
"input.text",
|
|
@@ -107,6 +108,9 @@ export function validateAgentRuntimeCapabilities(value) {
|
|
|
107
108
|
for (const path of DELIVERY_CAPABILITY_PATHS)
|
|
108
109
|
validateDelivery(path, readPath(value, path), errors);
|
|
109
110
|
const persistent = readPath(value, "lifecycle.persistent");
|
|
111
|
+
if (readPath(value, "lifecycle.forkWhileRunning") === true && readPath(value, "lifecycle.fork") !== true) {
|
|
112
|
+
errors.push("lifecycle.forkWhileRunning requires lifecycle.fork");
|
|
113
|
+
}
|
|
110
114
|
for (const path of ["lifecycle.resume", "lifecycle.attach"]) {
|
|
111
115
|
if (readPath(value, path) === true && persistent !== true)
|
|
112
116
|
errors.push(`${path} requires lifecycle.persistent`);
|
|
@@ -223,6 +227,7 @@ export function createMinimalAgentRuntimeCapabilities() {
|
|
|
223
227
|
attach: false,
|
|
224
228
|
listNativeSessions: false,
|
|
225
229
|
fork: false,
|
|
230
|
+
forkWhileRunning: false,
|
|
226
231
|
clone: false,
|
|
227
232
|
tree: false,
|
|
228
233
|
},
|
|
@@ -43,6 +43,8 @@ export function validateAgentRuntimeSessionContract(session) {
|
|
|
43
43
|
if (capabilities) {
|
|
44
44
|
requireMethod(capabilities.lifecycle.listNativeSessions, "lifecycle.listNativeSessions", "listSessions");
|
|
45
45
|
requireMethod(capabilities.lifecycle.fork, "lifecycle.fork", "forkSession");
|
|
46
|
+
requireMethod(capabilities.lifecycle.forkWhileRunning, "lifecycle.forkWhileRunning", "getForkCandidatesWhileRunning");
|
|
47
|
+
requireMethod(capabilities.lifecycle.forkWhileRunning, "lifecycle.forkWhileRunning", "forkSessionWhileRunning");
|
|
46
48
|
requireMethod(capabilities.lifecycle.clone, "lifecycle.clone", "cloneSession");
|
|
47
49
|
requireMethod(capabilities.lifecycle.tree, "lifecycle.tree", "getSessionTree");
|
|
48
50
|
requireMethod(capabilities.lifecycle.tree, "lifecycle.tree", "navigateSessionTree");
|
|
@@ -87,6 +87,7 @@ function nativeOperationToPiCompatibility(session, piboSessionId, result) {
|
|
|
87
87
|
selectedText: result.selectedText,
|
|
88
88
|
editorText: result.editorText,
|
|
89
89
|
summaryEntryId: result.summaryEntryId,
|
|
90
|
+
sourceSessionUnchanged: result.sourceSessionUnchanged,
|
|
90
91
|
};
|
|
91
92
|
}
|
|
92
93
|
function nativeSessionInfoToPiCompatibility(session, info) {
|
|
@@ -137,6 +138,7 @@ export class RuntimeRoutedSession {
|
|
|
137
138
|
activeThinkingIndex;
|
|
138
139
|
nextThinkingIndex = 0;
|
|
139
140
|
sessionIdentityOperationInFlight = false;
|
|
141
|
+
forkWhileRunningOperationInFlight = false;
|
|
140
142
|
forkCandidatesRequest;
|
|
141
143
|
primaryModel;
|
|
142
144
|
modelFallbacks;
|
|
@@ -215,10 +217,23 @@ export class RuntimeRoutedSession {
|
|
|
215
217
|
: event.action === "session.switch"
|
|
216
218
|
? "switch"
|
|
217
219
|
: undefined;
|
|
220
|
+
const status = this.getStatus();
|
|
221
|
+
const sourceHasWork = status.processing || status.streaming || status.queuedMessages > 0;
|
|
222
|
+
const forkWhileRunning = event.action === "session.fork"
|
|
223
|
+
&& sourceHasWork
|
|
224
|
+
&& Boolean(this.runtimeSession.controls?.forkSessionWhileRunning);
|
|
218
225
|
if (sessionIdentityOperation) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
226
|
+
if (forkWhileRunning) {
|
|
227
|
+
if (this.forkWhileRunningOperationInFlight) {
|
|
228
|
+
throw new Error("Pibo session already has a running-safe fork in progress.");
|
|
229
|
+
}
|
|
230
|
+
this.forkWhileRunningOperationInFlight = true;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
this.assertSessionIdentityOperationIdle(sessionIdentityOperation);
|
|
234
|
+
this.sessionIdentityOperationInFlight = true;
|
|
235
|
+
this.notifyState();
|
|
236
|
+
}
|
|
222
237
|
}
|
|
223
238
|
try {
|
|
224
239
|
if (sessionIdentityOperation)
|
|
@@ -237,7 +252,10 @@ export class RuntimeRoutedSession {
|
|
|
237
252
|
return output;
|
|
238
253
|
}
|
|
239
254
|
finally {
|
|
240
|
-
if (
|
|
255
|
+
if (forkWhileRunning) {
|
|
256
|
+
this.forkWhileRunningOperationInFlight = false;
|
|
257
|
+
}
|
|
258
|
+
else if (sessionIdentityOperation) {
|
|
241
259
|
this.sessionIdentityOperationInFlight = false;
|
|
242
260
|
this.notifyState();
|
|
243
261
|
this.startDrain();
|
|
@@ -280,6 +298,8 @@ export class RuntimeRoutedSession {
|
|
|
280
298
|
streaming: this.disposed ? false : status.streaming,
|
|
281
299
|
activeTools: [...status.enabledTools],
|
|
282
300
|
enabledTools: [...status.enabledTools],
|
|
301
|
+
enabledSkills: [...(this.options.statusResources?.enabledSkills ?? [])],
|
|
302
|
+
contextFiles: [...(this.options.statusResources?.contextFiles ?? [])],
|
|
283
303
|
cwd: status.cwd,
|
|
284
304
|
disposed: this.disposed,
|
|
285
305
|
thinkingLevel,
|
|
@@ -368,7 +388,25 @@ export class RuntimeRoutedSession {
|
|
|
368
388
|
async getForkCandidates() {
|
|
369
389
|
if (this.forkCandidatesRequest)
|
|
370
390
|
return await this.forkCandidatesRequest;
|
|
371
|
-
this.
|
|
391
|
+
if (this.sessionIdentityOperationInFlight) {
|
|
392
|
+
throw new Error("Pibo session already has a session identity operation in progress; cannot inspect fork candidates.");
|
|
393
|
+
}
|
|
394
|
+
const status = this.getStatus();
|
|
395
|
+
const sourceHasWork = status.processing || status.streaming || status.queuedMessages > 0;
|
|
396
|
+
if (sourceHasWork) {
|
|
397
|
+
const getForkCandidatesWhileRunning = this.runtimeSession.controls?.getForkCandidatesWhileRunning;
|
|
398
|
+
if (!getForkCandidatesWhileRunning)
|
|
399
|
+
this.assertSessionWorkIdle("inspect fork candidates");
|
|
400
|
+
const request = Promise.resolve().then(async () => await getForkCandidatesWhileRunning());
|
|
401
|
+
this.forkCandidatesRequest = request;
|
|
402
|
+
try {
|
|
403
|
+
return await request;
|
|
404
|
+
}
|
|
405
|
+
finally {
|
|
406
|
+
if (this.forkCandidatesRequest === request)
|
|
407
|
+
this.forkCandidatesRequest = undefined;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
372
410
|
const getForkCandidates = this.runtimeSession.controls?.getForkCandidates;
|
|
373
411
|
if (!getForkCandidates)
|
|
374
412
|
throw runtimeCapabilityError(this.runtimeSession, "native session fork candidates");
|
|
@@ -388,6 +426,12 @@ export class RuntimeRoutedSession {
|
|
|
388
426
|
}
|
|
389
427
|
}
|
|
390
428
|
async forkSession(entryId) {
|
|
429
|
+
if (this.forkWhileRunningOperationInFlight) {
|
|
430
|
+
const forkSessionWhileRunning = this.runtimeSession.controls?.forkSessionWhileRunning;
|
|
431
|
+
if (!forkSessionWhileRunning)
|
|
432
|
+
throw runtimeCapabilityError(this.runtimeSession, "forking completed history while running");
|
|
433
|
+
return nativeOperationToPiCompatibility(this.runtimeSession, this.piboSessionId, await forkSessionWhileRunning(entryId));
|
|
434
|
+
}
|
|
391
435
|
this.assertSessionWorkIdle("fork");
|
|
392
436
|
const forkSession = this.runtimeSession.controls?.forkSession;
|
|
393
437
|
if (!forkSession)
|
|
@@ -436,11 +480,26 @@ export class RuntimeRoutedSession {
|
|
|
436
480
|
return nativeOperationToPiCompatibility(this.runtimeSession, this.piboSessionId, await switchSession(params));
|
|
437
481
|
}
|
|
438
482
|
async setModel(model) {
|
|
439
|
-
const
|
|
483
|
+
const selected = await this.setRuntimeModelPreservingReasoning(model);
|
|
484
|
+
this.primaryModel = { ...selected };
|
|
485
|
+
return selected;
|
|
486
|
+
}
|
|
487
|
+
async setRuntimeModelPreservingReasoning(model) {
|
|
488
|
+
const controls = this.runtimeSession.controls;
|
|
489
|
+
const setModel = controls?.setModel;
|
|
440
490
|
if (!setModel)
|
|
441
491
|
throw runtimeCapabilityError(this.runtimeSession, "in-session model switching");
|
|
492
|
+
const priorReasoning = controls.getReasoning?.() ?? this.runtimeSession.getStatus().reasoning;
|
|
442
493
|
const selected = await setModel(model);
|
|
443
|
-
|
|
494
|
+
if (!priorReasoning?.supported || !priorReasoning.value || !controls.setReasoning)
|
|
495
|
+
return selected;
|
|
496
|
+
const currentReasoning = controls.getReasoning?.() ?? this.runtimeSession.getStatus().reasoning;
|
|
497
|
+
if (!currentReasoning?.supported || currentReasoning.value === priorReasoning.value)
|
|
498
|
+
return selected;
|
|
499
|
+
if (currentReasoning.availableValues?.length && !currentReasoning.availableValues.includes(priorReasoning.value)) {
|
|
500
|
+
return selected;
|
|
501
|
+
}
|
|
502
|
+
controls.setReasoning(priorReasoning.value);
|
|
444
503
|
return selected;
|
|
445
504
|
}
|
|
446
505
|
setThinkingLevel(level) {
|
|
@@ -751,9 +810,9 @@ export class RuntimeRoutedSession {
|
|
|
751
810
|
}
|
|
752
811
|
}
|
|
753
812
|
async promptWithModelFallbacks(event, inFlight) {
|
|
754
|
-
const
|
|
813
|
+
const canSetModel = Boolean(this.runtimeSession.controls?.setModel);
|
|
755
814
|
const fallbackModels = this.modelFallbacks.filter((model) => !sameModel(model, this.primaryModel));
|
|
756
|
-
if (!
|
|
815
|
+
if (!canSetModel || fallbackModels.length === 0) {
|
|
757
816
|
await this.runtimeSession.prompt({
|
|
758
817
|
text: event.text,
|
|
759
818
|
source: promptSource(event.source),
|
|
@@ -770,7 +829,7 @@ export class RuntimeRoutedSession {
|
|
|
770
829
|
return;
|
|
771
830
|
if (attempt > 0) {
|
|
772
831
|
try {
|
|
773
|
-
await
|
|
832
|
+
await this.setRuntimeModelPreservingReasoning(fallbackModels[attempt - 1]);
|
|
774
833
|
switchedModel = true;
|
|
775
834
|
}
|
|
776
835
|
catch {
|
|
@@ -807,7 +866,7 @@ export class RuntimeRoutedSession {
|
|
|
807
866
|
this.pendingProviderFailure = undefined;
|
|
808
867
|
if (switchedModel && this.primaryModel && !this.disposed) {
|
|
809
868
|
try {
|
|
810
|
-
await
|
|
869
|
+
await this.setRuntimeModelPreservingReasoning(this.primaryModel);
|
|
811
870
|
}
|
|
812
871
|
catch (error) {
|
|
813
872
|
console.warn(`Failed to restore primary model for Pibo session "${this.piboSessionId}": ${errorMessage(error)}`);
|
|
@@ -88,6 +88,7 @@ function codexNativeCapabilities(structuredUserInput) {
|
|
|
88
88
|
attach: true,
|
|
89
89
|
listNativeSessions: true,
|
|
90
90
|
fork: true,
|
|
91
|
+
forkWhileRunning: true,
|
|
91
92
|
clone: true,
|
|
92
93
|
tree: false,
|
|
93
94
|
},
|
|
@@ -313,6 +314,7 @@ export class CodexNativeThreadSession {
|
|
|
313
314
|
getCurrentSession: () => this.threads.getSnapshot(this.runtimeInstanceId),
|
|
314
315
|
listSessions: () => this.threads.list(this.runtimeInstanceId, this.cwd),
|
|
315
316
|
getForkCandidates: () => this.threads.getForkCandidates(),
|
|
317
|
+
getForkCandidatesWhileRunning: () => this.threads.getForkCandidatesWhileRunning(),
|
|
316
318
|
forkSession: async (entryId) => await this.runIdleOperation(async () => {
|
|
317
319
|
const result = await this.threads.fork(this.runtimeInstanceId, this.cwd, entryId, async (threadId) => await this.resourceDelivery.verifyThread(this.process.client, threadId));
|
|
318
320
|
if (result.current.nativeSessionId) {
|
|
@@ -321,6 +323,7 @@ export class CodexNativeThreadSession {
|
|
|
321
323
|
}
|
|
322
324
|
return result;
|
|
323
325
|
}),
|
|
326
|
+
forkSessionWhileRunning: async (entryId) => await this.threads.forkWhileRunning(this.runtimeInstanceId, this.cwd, entryId, async (threadId) => await this.resourceDelivery.verifyThread(this.process.client, threadId)),
|
|
324
327
|
cloneSession: async () => await this.runIdleOperation(async () => {
|
|
325
328
|
const result = await this.threads.clone(this.runtimeInstanceId, this.cwd, async (threadId) => await this.resourceDelivery.verifyThread(this.process.client, threadId));
|
|
326
329
|
this.settings.attachThread(this.threads.thread.id, this.threads.configuration);
|
|
@@ -303,6 +303,12 @@ export class CodexNativeThreadController {
|
|
|
303
303
|
getForkCandidates() {
|
|
304
304
|
return codexThreadForkCandidates(this.currentThread);
|
|
305
305
|
}
|
|
306
|
+
getForkCandidatesWhileRunning() {
|
|
307
|
+
return codexThreadForkCandidates({
|
|
308
|
+
...this.currentThread,
|
|
309
|
+
turns: this.currentThread.turns.filter((turn) => turn.status !== "inProgress"),
|
|
310
|
+
});
|
|
311
|
+
}
|
|
306
312
|
setStatus(status) {
|
|
307
313
|
this.currentThread = { ...this.currentThread, status: structuredClone(status) };
|
|
308
314
|
this.knownThreads.set(this.currentThread.id, structuredClone(this.currentThread));
|
|
@@ -372,10 +378,24 @@ export class CodexNativeThreadController {
|
|
|
372
378
|
text: legacyText ?? `Codex turn ${entryId}`,
|
|
373
379
|
});
|
|
374
380
|
}
|
|
381
|
+
async forkWhileRunning(runtimeInstanceId, workspace, entryId, validateThread) {
|
|
382
|
+
if (!entryId.trim())
|
|
383
|
+
throw new Error("Codex thread fork requires a native user-message id.");
|
|
384
|
+
const target = codexThreadForkTargets({
|
|
385
|
+
...this.currentThread,
|
|
386
|
+
turns: this.currentThread.turns.filter((turn) => turn.status !== "inProgress"),
|
|
387
|
+
}).find((candidate) => candidate.entryId === entryId);
|
|
388
|
+
if (!target)
|
|
389
|
+
throw new Error("Fork target is not a completed user message.");
|
|
390
|
+
const result = !target.previousTurnId
|
|
391
|
+
? this.branchBeforeFirstTurn(runtimeInstanceId, workspace, target)
|
|
392
|
+
: await this.forkAt(runtimeInstanceId, workspace, target.previousTurnId, validateThread, target, false);
|
|
393
|
+
return { ...result, sourceSessionUnchanged: true };
|
|
394
|
+
}
|
|
375
395
|
async clone(runtimeInstanceId, workspace, validateThread) {
|
|
376
396
|
return await this.forkAt(runtimeInstanceId, workspace, undefined, validateThread);
|
|
377
397
|
}
|
|
378
|
-
async forkAt(runtimeInstanceId, workspace, lastTurnId, validateThread, selectedTarget) {
|
|
398
|
+
async forkAt(runtimeInstanceId, workspace, lastTurnId, validateThread, selectedTarget, adoptFork = true) {
|
|
379
399
|
const previousThread = this.currentThread;
|
|
380
400
|
const previous = codexThreadSnapshot(runtimeInstanceId, previousThread);
|
|
381
401
|
const params = {
|
|
@@ -398,10 +418,12 @@ export class CodexNativeThreadController {
|
|
|
398
418
|
throw new CodexNativeThreadProtocolError("Codex thread/fork returned the source thread id.");
|
|
399
419
|
}
|
|
400
420
|
await validateThread?.(forked.id);
|
|
401
|
-
|
|
421
|
+
if (adoptFork) {
|
|
422
|
+
this.knownThreads.set(previousThread.id, structuredClone(previousThread));
|
|
423
|
+
this.currentThread = forked;
|
|
424
|
+
this.currentConfiguration = selected.configuration;
|
|
425
|
+
}
|
|
402
426
|
this.knownThreads.set(forked.id, structuredClone(forked));
|
|
403
|
-
this.currentThread = forked;
|
|
404
|
-
this.currentConfiguration = selected.configuration;
|
|
405
427
|
return {
|
|
406
428
|
previous,
|
|
407
429
|
current: codexThreadSnapshot(runtimeInstanceId, forked),
|
|
@@ -46,6 +46,7 @@ export const PI_AGENT_RUNTIME_CAPABILITIES = {
|
|
|
46
46
|
attach: true,
|
|
47
47
|
listNativeSessions: true,
|
|
48
48
|
fork: true,
|
|
49
|
+
forkWhileRunning: true,
|
|
49
50
|
clone: true,
|
|
50
51
|
tree: true,
|
|
51
52
|
},
|
|
@@ -176,6 +177,7 @@ function nativeOperationFromPi(runtimeInstanceId, result) {
|
|
|
176
177
|
previous: nativeSnapshotFromPi(runtimeInstanceId, result.previous),
|
|
177
178
|
current: nativeSnapshotFromPi(runtimeInstanceId, result.current),
|
|
178
179
|
cancelled: result.cancelled,
|
|
180
|
+
sourceSessionUnchanged: result.sourceSessionUnchanged,
|
|
179
181
|
selectedText: result.selectedText,
|
|
180
182
|
editorText: result.editorText,
|
|
181
183
|
summaryEntryId: result.summaryEntryId,
|
|
@@ -439,7 +441,9 @@ class PiAgentRuntimeSession {
|
|
|
439
441
|
getCurrentSession: () => nativeSnapshotFromPi(this.runtimeInstanceId, this.routed.getCurrentSession()),
|
|
440
442
|
listSessions: async () => (await this.routed.listSessions()).map((info) => nativeSessionInfoFromPi(this.runtimeInstanceId, info)),
|
|
441
443
|
getForkCandidates: () => this.routed.getForkCandidates(),
|
|
444
|
+
getForkCandidatesWhileRunning: () => this.routed.getForkCandidatesWhileRunning(),
|
|
442
445
|
forkSession: async (entryId) => nativeOperationFromPi(this.runtimeInstanceId, await this.routed.forkSession(entryId)),
|
|
446
|
+
forkSessionWhileRunning: async (entryId) => nativeOperationFromPi(this.runtimeInstanceId, await this.routed.forkSessionWhileRunning(entryId)),
|
|
443
447
|
cloneSession: async () => nativeOperationFromPi(this.runtimeInstanceId, await this.routed.cloneSession()),
|
|
444
448
|
getSessionTree: () => {
|
|
445
449
|
const result = this.routed.getSessionTree();
|
|
@@ -1239,6 +1239,52 @@ export class RoutedSession {
|
|
|
1239
1239
|
this.assertSessionIdentityOperationIdle("inspect fork candidates");
|
|
1240
1240
|
return this.runtime.session.getUserMessagesForForking();
|
|
1241
1241
|
}
|
|
1242
|
+
getForkCandidatesWhileRunning() {
|
|
1243
|
+
const candidates = this.runtime.session.getUserMessagesForForking();
|
|
1244
|
+
return this.getStatus().processing || this.getStatus().streaming
|
|
1245
|
+
? candidates.slice(0, -1)
|
|
1246
|
+
: candidates;
|
|
1247
|
+
}
|
|
1248
|
+
async forkSessionWhileRunning(entryId) {
|
|
1249
|
+
this.assertActive();
|
|
1250
|
+
const sourceManager = this.runtime.session.sessionManager;
|
|
1251
|
+
const sourceFile = sourceManager.getSessionFile();
|
|
1252
|
+
if (!sourceManager.isPersisted() || !sourceFile || !existsSync(sourceFile)) {
|
|
1253
|
+
throw new Error("A running Pi session can only fork from persisted history.");
|
|
1254
|
+
}
|
|
1255
|
+
const selected = this.getForkCandidatesWhileRunning().find((candidate) => candidate.entryId === entryId);
|
|
1256
|
+
if (!selected)
|
|
1257
|
+
throw new Error("Fork target is not a completed user message.");
|
|
1258
|
+
const selectedEntry = sourceManager.getEntry(entryId);
|
|
1259
|
+
if (!selectedEntry || selectedEntry.type !== "message" || selectedEntry.message.role !== "user") {
|
|
1260
|
+
throw new Error("Invalid entry ID for forking");
|
|
1261
|
+
}
|
|
1262
|
+
const previous = this.createSessionSnapshot();
|
|
1263
|
+
const targetLeafId = selectedEntry.parentId;
|
|
1264
|
+
let forkedManager;
|
|
1265
|
+
if (!targetLeafId) {
|
|
1266
|
+
forkedManager = SessionManager.create(this.runtime.cwd, sourceManager.getSessionDir());
|
|
1267
|
+
forkedManager.newSession({ parentSession: sourceFile });
|
|
1268
|
+
}
|
|
1269
|
+
else {
|
|
1270
|
+
forkedManager = SessionManager.open(sourceFile, sourceManager.getSessionDir(), this.runtime.cwd);
|
|
1271
|
+
if (!forkedManager.getEntry(targetLeafId)) {
|
|
1272
|
+
throw new Error("Fork target is not available in persisted history.");
|
|
1273
|
+
}
|
|
1274
|
+
const forkedSessionPath = forkedManager.createBranchedSession(targetLeafId);
|
|
1275
|
+
if (!forkedSessionPath)
|
|
1276
|
+
throw new Error("Failed to create forked session");
|
|
1277
|
+
}
|
|
1278
|
+
materializeForkedSession(forkedManager);
|
|
1279
|
+
return {
|
|
1280
|
+
piboSessionId: this.piboSessionId,
|
|
1281
|
+
previous,
|
|
1282
|
+
current: this.createSessionManagerSnapshot(forkedManager),
|
|
1283
|
+
cancelled: false,
|
|
1284
|
+
sourceSessionUnchanged: true,
|
|
1285
|
+
selectedText: selected.text,
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1242
1288
|
async forkSession(entryId) {
|
|
1243
1289
|
this.assertActive();
|
|
1244
1290
|
this.assertSessionWorkIdle("fork");
|
|
@@ -1809,13 +1855,15 @@ export class RoutedSession {
|
|
|
1809
1855
|
}
|
|
1810
1856
|
createSessionSnapshot() {
|
|
1811
1857
|
const session = this.runtime.session;
|
|
1812
|
-
|
|
1858
|
+
return this.createSessionManagerSnapshot(session.sessionManager, session.sessionName);
|
|
1859
|
+
}
|
|
1860
|
+
createSessionManagerSnapshot(manager, sessionName = manager.getSessionName()) {
|
|
1813
1861
|
return {
|
|
1814
|
-
piSessionId:
|
|
1815
|
-
sessionFile:
|
|
1862
|
+
piSessionId: manager.getSessionId(),
|
|
1863
|
+
sessionFile: manager.getSessionFile(),
|
|
1816
1864
|
leafId: manager.getLeafId(),
|
|
1817
|
-
cwd:
|
|
1818
|
-
sessionName
|
|
1865
|
+
cwd: manager.getCwd(),
|
|
1866
|
+
sessionName,
|
|
1819
1867
|
parentSessionFile: manager.getHeader()?.parentSession,
|
|
1820
1868
|
};
|
|
1821
1869
|
}
|
|
@@ -13,7 +13,7 @@ export function roomResourcePath(pathname) {
|
|
|
13
13
|
try {
|
|
14
14
|
const roomId = decodeURIComponent(parts[0]);
|
|
15
15
|
const child = parts[1] ? decodeURIComponent(parts[1]) : undefined;
|
|
16
|
-
if (child && child !== "events" && child !== "messages" && child !== "read")
|
|
16
|
+
if (child && child !== "events" && child !== "messages" && child !== "read" && child !== "order")
|
|
17
17
|
return undefined;
|
|
18
18
|
return { roomId, child };
|
|
19
19
|
}
|
|
@@ -246,52 +246,26 @@ export function userSkillResourceId(pathname) {
|
|
|
246
246
|
throw new PiboWebHttpError("Invalid user skill id", 400);
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
|
-
export function
|
|
250
|
-
const prefix = `${CHAT_WEB_API_PREFIX}/
|
|
251
|
-
if (!pathname.startsWith(prefix))
|
|
252
|
-
return undefined;
|
|
253
|
-
const parts = pathname.slice(prefix.length).split("/").filter(Boolean).map((part) => decodeURIComponent(part));
|
|
254
|
-
if (!parts[0])
|
|
255
|
-
return undefined;
|
|
256
|
-
return { projectId: parts[0], ...(parts[1] ? { child: parts[1] } : {}) };
|
|
257
|
-
}
|
|
258
|
-
export function projectWorkflowSessionStartResource(pathname) {
|
|
259
|
-
const prefix = `${CHAT_WEB_API_PREFIX}/projects/`;
|
|
249
|
+
export function sessionWorkflowResource(pathname) {
|
|
250
|
+
const prefix = `${CHAT_WEB_API_PREFIX}/sessions/`;
|
|
260
251
|
if (!pathname.startsWith(prefix))
|
|
261
252
|
return undefined;
|
|
262
253
|
const parts = pathname.slice(prefix.length).split("/");
|
|
263
|
-
if (parts.length
|
|
254
|
+
if (parts.length < 2 || parts.length > 3 || !parts[0] || parts[1] !== "workflow")
|
|
264
255
|
return undefined;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
catch {
|
|
269
|
-
throw new PiboWebHttpError("Invalid Project workflow session start path", 400);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
export function projectWorkflowHumanActionsResource(pathname) {
|
|
273
|
-
const prefix = `${CHAT_WEB_API_PREFIX}/projects/`;
|
|
274
|
-
if (!pathname.startsWith(prefix))
|
|
275
|
-
return undefined;
|
|
276
|
-
const parts = pathname.slice(prefix.length).split("/");
|
|
277
|
-
if (parts.length !== 4 || !parts[0] || parts[1] !== "workflow-sessions" || !parts[2] || parts[3] !== "human-actions")
|
|
256
|
+
const action = parts[2];
|
|
257
|
+
if (action !== undefined && action !== "start" && action !== "human-actions")
|
|
278
258
|
return undefined;
|
|
279
259
|
try {
|
|
280
|
-
return {
|
|
260
|
+
return {
|
|
261
|
+
piboSessionId: decodeURIComponent(parts[0]),
|
|
262
|
+
...(action ? { action } : {}),
|
|
263
|
+
};
|
|
281
264
|
}
|
|
282
265
|
catch {
|
|
283
|
-
throw new PiboWebHttpError("Invalid
|
|
266
|
+
throw new PiboWebHttpError("Invalid Workflow session path", 400);
|
|
284
267
|
}
|
|
285
268
|
}
|
|
286
|
-
export function projectSessionResourceId(pathname) {
|
|
287
|
-
const prefix = `${CHAT_WEB_API_PREFIX}/project-sessions/`;
|
|
288
|
-
if (!pathname.startsWith(prefix))
|
|
289
|
-
return undefined;
|
|
290
|
-
const encodedId = pathname.slice(prefix.length);
|
|
291
|
-
if (!encodedId || encodedId.includes("/"))
|
|
292
|
-
return undefined;
|
|
293
|
-
return decodeURIComponent(encodedId);
|
|
294
|
-
}
|
|
295
269
|
export function sessionResourceId(pathname) {
|
|
296
270
|
const prefix = `${CHAT_WEB_API_PREFIX}/sessions/`;
|
|
297
271
|
if (!pathname.startsWith(prefix))
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
|
-
import { isAbsolute
|
|
2
|
+
import { isAbsolute } from "node:path";
|
|
3
3
|
import { savePiboModelDefaults } from "../../core/model-defaults.js";
|
|
4
4
|
import { DEFAULT_AGENT_RUNTIME_INSTANCE_ID } from "../../core/profiles.js";
|
|
5
5
|
import { isPiboThinkingLevel } from "../../core/thinking.js";
|
|
6
6
|
import { PiboWebHttpError } from "../../web/http.js";
|
|
7
7
|
import { listPiPackages } from "../../pi-packages/store.js";
|
|
8
8
|
import { withChatWebArchived, withChatWebSessionPinned } from "./session-metadata.js";
|
|
9
|
-
import { isDefaultPiboRoom, withPiboRoomArchived, withPiboRoomWorkspace } from "./types/rooms.js";
|
|
9
|
+
import { isDefaultPiboRoom, withPiboRoomArchived, withPiboRoomPinned, withPiboRoomWorkspace } from "./types/rooms.js";
|
|
10
10
|
import { isValidCustomAgentName } from "./agent-store.js";
|
|
11
11
|
export function normalizeRoomName(value, fallback = "New Chat") {
|
|
12
12
|
if (value === undefined)
|
|
@@ -595,52 +595,6 @@ export function updateChatModelDefaults(body, cwd = process.cwd()) {
|
|
|
595
595
|
subagentFast: normalizeOptionalBoolean(body.subagentFast, "subagentFast"),
|
|
596
596
|
}, cwd);
|
|
597
597
|
}
|
|
598
|
-
const PROJECT_SESSION_PATCH_FIELDS = new Set([
|
|
599
|
-
"title",
|
|
600
|
-
"archived",
|
|
601
|
-
]);
|
|
602
|
-
export function assertProjectSessionPatchFields(body) {
|
|
603
|
-
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
604
|
-
throw new PiboWebHttpError("Invalid JSON body", 400);
|
|
605
|
-
for (const key of Object.keys(body)) {
|
|
606
|
-
if (!PROJECT_SESSION_PATCH_FIELDS.has(key)) {
|
|
607
|
-
throw new PiboWebHttpError(`Unsupported project session update field: ${key}. Project workflow selection and configuration are immutable; create a new configured session to change workflow, input, prompt, model, thinking, or fast-mode values.`, 400);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
export function normalizeProjectPath(value) {
|
|
612
|
-
if (typeof value !== "string" || !value.trim())
|
|
613
|
-
throw new PiboWebHttpError("Project folder is required", 400);
|
|
614
|
-
let projectPath = value.trim();
|
|
615
|
-
if (projectPath === "~")
|
|
616
|
-
projectPath = process.env.HOME ?? projectPath;
|
|
617
|
-
else if (projectPath.startsWith("~/"))
|
|
618
|
-
projectPath = `${process.env.HOME ?? ""}${projectPath.slice(1)}`;
|
|
619
|
-
if (!isAbsolute(projectPath))
|
|
620
|
-
throw new PiboWebHttpError("Project folder must be an absolute path, e.g. ~/code/my-project or /home/me/code/my-project", 400);
|
|
621
|
-
return resolve(projectPath);
|
|
622
|
-
}
|
|
623
|
-
export function normalizeProjectDescription(value) {
|
|
624
|
-
if (value === undefined || value === null)
|
|
625
|
-
return undefined;
|
|
626
|
-
if (typeof value !== "string")
|
|
627
|
-
throw new PiboWebHttpError("Project description must be a string", 400);
|
|
628
|
-
return value.trim() || undefined;
|
|
629
|
-
}
|
|
630
|
-
export function normalizeProjectArchived(value) {
|
|
631
|
-
if (value === undefined)
|
|
632
|
-
return undefined;
|
|
633
|
-
if (typeof value !== "boolean")
|
|
634
|
-
throw new PiboWebHttpError("Project archived flag must be boolean", 400);
|
|
635
|
-
return value;
|
|
636
|
-
}
|
|
637
|
-
export function normalizeProjectSessionArchived(value) {
|
|
638
|
-
if (value === undefined)
|
|
639
|
-
return undefined;
|
|
640
|
-
if (typeof value !== "boolean")
|
|
641
|
-
throw new PiboWebHttpError("Project session archived flag must be boolean", 400);
|
|
642
|
-
return value;
|
|
643
|
-
}
|
|
644
598
|
export function normalizeSessionTitle(value) {
|
|
645
599
|
if (value === undefined)
|
|
646
600
|
return undefined;
|
|
@@ -712,6 +666,12 @@ export function createRoomUpdate(room, body) {
|
|
|
712
666
|
metadata = withPiboRoomWorkspace(metadata, workspace ?? undefined);
|
|
713
667
|
metadataChanged = true;
|
|
714
668
|
}
|
|
669
|
+
if (body.pinned !== undefined) {
|
|
670
|
+
if (typeof body.pinned !== "boolean")
|
|
671
|
+
throw new PiboWebHttpError("Room pinned flag must be boolean", 400);
|
|
672
|
+
metadata = withPiboRoomPinned(metadata, body.pinned);
|
|
673
|
+
metadataChanged = true;
|
|
674
|
+
}
|
|
715
675
|
if (metadataChanged)
|
|
716
676
|
update.metadata = metadata;
|
|
717
677
|
if (Object.keys(update).length === 0) {
|