@pasko70/pibo 3.0.2 → 3.1.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.
Files changed (72) hide show
  1. package/compute-image/Dockerfile +47 -0
  2. package/compute-image/Dockerfile.dockerignore +5 -0
  3. package/dist/agent-runtime/contract.js +78 -28
  4. package/dist/agent-runtime/portable-history.js +19 -9
  5. package/dist/agent-runtime/registry.js +8 -2
  6. package/dist/agent-runtime/routed-session.js +12 -6
  7. package/dist/agent-runtimes/pi/routed-session.js +10 -4
  8. package/dist/apps/chat/agent-store.js +55 -3
  9. package/dist/apps/chat/data/project-service.js +119 -15
  10. package/dist/apps/chat/data/room-service.js +21 -0
  11. package/dist/apps/chat/loop-api.js +10 -2
  12. package/dist/apps/chat/web-app.js +84 -25
  13. package/dist/apps/chat-ui/assets/{dist-CvaPTBTN.js → dist-CUQJqggN.js} +1 -1
  14. package/dist/apps/chat-ui/assets/{dist-BPotHecb.js → dist-ClUlQWYN.js} +1 -1
  15. package/dist/apps/chat-ui/assets/{dist-BzqQKeVO.js → dist-Djul9BmZ.js} +1 -1
  16. package/dist/apps/chat-ui/assets/{dist-paagejNj.js → dist-GD0JGdCi.js} +1 -1
  17. package/dist/apps/chat-ui/assets/{dist-B6GZgWSj.js → dist-W5HOqHym.js} +1 -1
  18. package/dist/apps/chat-ui/assets/index-BcjkX-iP.js +228 -0
  19. package/dist/apps/chat-ui/assets/index-CmqRSbBU.css +1 -0
  20. package/dist/apps/chat-ui/index.html +2 -2
  21. package/dist/apps/chat-vscode-web/assets/index-JvrPUGvI.js +43 -0
  22. package/dist/apps/chat-vscode-web/index.html +1 -1
  23. package/dist/apps/cli-ui/InkSessionApp.js +111 -12
  24. package/dist/compute/cli.js +35 -16
  25. package/dist/compute/docker.js +341 -94
  26. package/dist/config/config.js +3 -0
  27. package/dist/core/output-render-sequence.js +148 -1
  28. package/dist/core/session-router.js +33 -105
  29. package/dist/data/ingest-service.js +14 -6
  30. package/dist/data/pibo-store.js +8 -1
  31. package/dist/data/schema.js +135 -5
  32. package/dist/debug/agents.js +91 -89
  33. package/dist/debug/index.js +2 -0
  34. package/dist/debug/pty.js +127 -48
  35. package/dist/gateway/cli.js +4 -0
  36. package/dist/loops/channel.js +3 -1
  37. package/dist/loops/cli.js +2 -1
  38. package/dist/loops/service.js +90 -11
  39. package/dist/loops/store.js +100 -74
  40. package/dist/mcp/agent-context.js +13 -26
  41. package/dist/mcp/commands/info.js +3 -1
  42. package/dist/mcp/config-command.js +46 -2
  43. package/dist/mcp/config.js +18 -4
  44. package/dist/plugins/context-files-store.js +6 -6
  45. package/dist/previews/base-url.js +34 -0
  46. package/dist/previews/config.js +2 -32
  47. package/dist/ralph/store.js +5 -0
  48. package/dist/reliability/store.js +174 -111
  49. package/dist/session-ui/terminalRows.js +2 -1
  50. package/dist/sessions/pibo-data-store.js +81 -0
  51. package/dist/subagents/observation-query.js +121 -0
  52. package/dist/tools/agent-browser-leases.js +58 -23
  53. package/dist/tools/agent-browser-wrapper.js +1 -1
  54. package/dist/tools/browser-use-leases.js +129 -16
  55. package/dist/tools/browser-use-wrapper.js +1 -1
  56. package/dist/tools/index.js +27 -11
  57. package/dist/tools/python-runtime.js +10 -3
  58. package/dist/tools/registry.js +1 -1
  59. package/dist/tools/runtime/node-backend.js +16 -5
  60. package/dist/tools/runtime/node-worker-source.js +112 -33
  61. package/dist/tools/runtime/python-backend.js +16 -5
  62. package/dist/tools/runtime/python-worker-source.js +167 -16
  63. package/dist/tools/runtime/registry.js +23 -10
  64. package/dist/user-skills/store.js +0 -1
  65. package/npm-shrinkwrap.json +9 -2
  66. package/package.json +8 -2
  67. package/scripts/docker-entrypoint.sh +46 -0
  68. package/scripts/prepare-agent-browser-wrapper.sh +70 -0
  69. package/scripts/prepare-browser-use-wrapper.sh +255 -0
  70. package/dist/apps/chat-ui/assets/index-6JJV-eic.js +0 -228
  71. package/dist/apps/chat-ui/assets/index-CeL9JPP5.css +0 -1
  72. package/dist/apps/chat-vscode-web/assets/index-U-MSErGa.js +0 -43
@@ -2,7 +2,7 @@ import { PiboWebHttpError, readJsonBody, responseJson } from '../../web/http.js'
2
2
  import { getPiboLoopService } from '../../loops/channel.js';
3
3
  import { listLoopJobTemplates } from '../../loops/templates.js';
4
4
  import { isPiboThinkingLevel } from '../../core/thinking.js';
5
- import { normalizeLoopStopPolicy } from '../../loops/store.js';
5
+ import { normalizeLoopStopPolicy, PiboLoopActiveRunModeChangeError } from '../../loops/store.js';
6
6
  import { isPiboRoomArchived } from './types/rooms.js';
7
7
  const CHAT_WEB_API_PREFIX = '/api/chat';
8
8
  function requireSameOriginJsonRequest(request) { const contentType = request.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase(); if (contentType !== 'application/json')
@@ -184,7 +184,15 @@ export async function handleChatLoopApiRequest(options) {
184
184
  throw new PiboWebHttpError('Loop job not found', 404);
185
185
  if ((patch.mode ?? existing.mode) === 'ralph' && ((patch.tokenBudget !== undefined && patch.tokenBudget !== null) || (patch.tokenReserve !== undefined && patch.tokenReserve !== null)))
186
186
  throw new PiboWebHttpError('tokenBudget and tokenReserve are only available for goal mode', 400);
187
- const job = loopStore.updateJob(resource.id, patch);
187
+ let job;
188
+ try {
189
+ job = loopStore.updateJob(resource.id, patch);
190
+ }
191
+ catch (error) {
192
+ if (error instanceof PiboLoopActiveRunModeChangeError)
193
+ throw new PiboWebHttpError(error.message, 409);
194
+ throw error;
195
+ }
188
196
  if (!job)
189
197
  throw new PiboWebHttpError('Loop job not found', 404);
190
198
  return responseJson({ job: serializeJob(job) });
@@ -19,7 +19,7 @@ import { DEFAULT_TRACE_EVENTS_PAGE_SIZE, annotateTracePage, etagForVersion, esti
19
19
  import { TRACE_V2_DEFAULT_TIMELINE_LIMIT, TRACE_V2_MAX_TIMELINE_LIMIT, TRACE_V2_PAYLOAD_DEFAULT_LIMIT_BYTES, TRACE_V2_PAYLOAD_MAX_LIMIT_BYTES, TRACE_V2_RAW_EVENTS_DEFAULT_LIMIT, TRACE_V2_RAW_EVENTS_MAX_LIMIT, TRACE_V2_TIMELINE_HARD_BYTES, TRACE_IMAGE_MAX_COUNT, parseTracePayloadRef, readTraceImagePayload, readTracePayloadChunk, traceRawEventsPageFromEvents, traceTimelinePageFromView, } from "./trace-v2.js";
20
20
  import { isChatWebSessionArchived } from "./session-metadata.js";
21
21
  import { withWorkflowSessionKind } from "../../sessions/workflow-session-kind.js";
22
- import { CustomAgentStore, createDefaultCustomAgentStore, previewCustomAgentCreate, previewCustomAgentUpdate, } from "./agent-store.js";
22
+ import { CustomAgentTargetReferenceError, CustomAgentStore, createDefaultCustomAgentStore, previewCustomAgentCreate, previewCustomAgentUpdate, } from "./agent-store.js";
23
23
  import { loadPiboModelDefaults, } from "../../core/model-defaults.js";
24
24
  import { inspectPiboContextBuild } from "../../core/context-build.js";
25
25
  import { isPiboThinkingLevel } from "../../core/thinking.js";
@@ -35,7 +35,7 @@ import { ScopedUserSkillManager } from "../../user-skills/manager.js";
35
35
  import { ChatDataIngestService, outputIdempotencyKey, outputPersistenceDeliveryKey } from "../../data/ingest-service.js";
36
36
  import { ChatEventCommandService } from "./data/event-command-service.js";
37
37
  import { ChatReadStateService } from "./data/read-state-service.js";
38
- import { ChatRoomService } from "./data/room-service.js";
38
+ import { ChatRoomService, PiboRoomHierarchyCycleError } from "./data/room-service.js";
39
39
  import { ChatSessionQueryService } from "./data/session-query-service.js";
40
40
  import { ChatTimelineQueryService } from "./data/timeline-query-service.js";
41
41
  import { ChatHistoryQueryService } from "./data/history-query-service.js";
@@ -2352,6 +2352,17 @@ function normalizeAgentDeleteConfirmation(value) {
2352
2352
  }
2353
2353
  return value.trim();
2354
2354
  }
2355
+ function requireCustomAgentNotTargeted(state, agent, options = {}) {
2356
+ const dependents = state.agentStore.listReferencingAgents(agent.id)
2357
+ .filter((dependent) => !options.activeOnly || !dependent.archivedAt);
2358
+ if (dependents.length === 0)
2359
+ return;
2360
+ const error = new CustomAgentTargetReferenceError(agent.profileName, dependents.map((dependent) => dependent.profileName));
2361
+ const message = options.activeOnly
2362
+ ? error.message.replace("targeted by custom agents", "targeted by active custom agents")
2363
+ : error.message;
2364
+ throw new PiboWebHttpError(message, 409);
2365
+ }
2355
2366
  async function deleteSessionsForAgentProfile(state, context, webSession, profileNames) {
2356
2367
  const deleteSession = context.channelContext.deleteSession;
2357
2368
  if (!deleteSession)
@@ -2371,10 +2382,11 @@ async function deleteSessionsForAgentProfile(state, context, webSession, profile
2371
2382
  }
2372
2383
  }
2373
2384
  const orderedIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
2374
- for (const id of orderedIds)
2375
- await deleteSession(id);
2376
- state.sessionQuery.deleteSessions(orderedIds);
2377
- state.eventCommands.deleteSessions(orderedIds);
2385
+ for (const id of orderedIds) {
2386
+ await state.projectService.deleteProjectSessionWithCanonicalDelete(id, () => deleteSession(id));
2387
+ state.sessionQuery.deleteSessions([id]);
2388
+ state.eventCommands.deleteSessions([id]);
2389
+ }
2378
2390
  for (const id of orderedIds)
2379
2391
  disposeSessionStreamState(state, id);
2380
2392
  return orderedIds;
@@ -2397,10 +2409,11 @@ async function deleteSessionSubtree(state, context, webSession, rootSession) {
2397
2409
  }
2398
2410
  }
2399
2411
  const orderedIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
2400
- for (const id of orderedIds)
2401
- await deleteSession(id);
2402
- state.sessionQuery.deleteSessions(orderedIds);
2403
- state.eventCommands.deleteSessions(orderedIds);
2412
+ for (const id of orderedIds) {
2413
+ await state.projectService.deleteProjectSessionWithCanonicalDelete(id, () => deleteSession(id));
2414
+ state.sessionQuery.deleteSessions([id]);
2415
+ state.eventCommands.deleteSessions([id]);
2416
+ }
2404
2417
  for (const id of orderedIds)
2405
2418
  disposeSessionStreamState(state, id);
2406
2419
  return orderedIds;
@@ -2437,10 +2450,11 @@ async function deleteRoomTree(state, context, webSession, room, confirmName) {
2437
2450
  }
2438
2451
  }
2439
2452
  const orderedSessionIds = [...ids].sort((left, right) => sessionDepth(sessionsById.get(right), sessionsById) - sessionDepth(sessionsById.get(left), sessionsById));
2440
- for (const id of orderedSessionIds)
2441
- await deleteSession(id);
2442
- state.sessionQuery.deleteSessions(orderedSessionIds);
2443
- state.eventCommands.deleteSessions(orderedSessionIds);
2453
+ for (const id of orderedSessionIds) {
2454
+ await state.projectService.deleteProjectSessionWithCanonicalDelete(id, () => deleteSession(id));
2455
+ state.sessionQuery.deleteSessions([id]);
2456
+ state.eventCommands.deleteSessions([id]);
2457
+ }
2444
2458
  for (const id of orderedSessionIds)
2445
2459
  disposeSessionStreamState(state, id);
2446
2460
  state.eventCommands.deleteRooms(roomIds);
@@ -3961,7 +3975,9 @@ export function createChatWebApp(options = {}) {
3961
3975
  const webSession = await requireSession(request, context);
3962
3976
  const body = await readJsonBody(request);
3963
3977
  try {
3964
- requireSharedProject(state, webSession, projectResource.projectId, { includeArchived: true });
3978
+ const existingProject = requireSharedProject(state, webSession, projectResource.projectId, { includeArchived: true });
3979
+ if (existingProject.metadata.default === true)
3980
+ throw new PiboWebHttpError("Project Manager cannot be changed", 400);
3965
3981
  const project = state.projectService.updateProject(projectResource.projectId, {
3966
3982
  ...(body.name !== undefined ? { name: normalizeRoomName(body.name) } : {}),
3967
3983
  ...(body.description !== undefined ? { description: normalizeProjectDescription(body.description) ?? null } : {}),
@@ -3982,7 +3998,9 @@ export function createChatWebApp(options = {}) {
3982
3998
  const webSession = await requireSession(request, context);
3983
3999
  const body = await readJsonBody(request);
3984
4000
  try {
3985
- requireSharedProject(state, webSession, projectResource.projectId, { includeArchived: true });
4001
+ const project = requireSharedProject(state, webSession, projectResource.projectId, { includeArchived: true });
4002
+ if (project.metadata.default === true)
4003
+ throw new PiboWebHttpError("Project Manager cannot be deleted", 400);
3986
4004
  return responseJson(state.projectService.deleteProject(projectResource.projectId, {
3987
4005
  confirmName: normalizeRoomDeleteConfirmation(body.confirmName),
3988
4006
  deleteFiles: body.deleteFiles === true,
@@ -4272,22 +4290,43 @@ export function createChatWebApp(options = {}) {
4272
4290
  if (!rootPiboSessionId)
4273
4291
  throw new PiboWebHttpError("rootPiboSessionId is required", 400);
4274
4292
  requireSharedSession(context, rootPiboSessionId);
4275
- if (!context.channelContext.snapshotSignalTree || !context.channelContext.subscribeSignalTree) {
4293
+ const includeStatuses = parseBooleanSearchParam(url, "includeStatuses");
4294
+ if (!context.channelContext.snapshotSignalTree
4295
+ || !context.channelContext.subscribeSignalTree
4296
+ || (includeStatuses && (!context.channelContext.snapshotSignalStatuses || !context.channelContext.subscribeSignalStatuses))) {
4276
4297
  throw new PiboWebHttpError("Signal registry is not available", 503);
4277
4298
  }
4278
- let unsubscribe;
4299
+ let unsubscribeTree;
4300
+ let unsubscribeStatuses;
4279
4301
  let heartbeat;
4302
+ let closed = false;
4280
4303
  const stream = new ReadableStream({
4281
4304
  start: (controller) => {
4282
4305
  writeJsonSse(controller, "signal_snapshot", context.channelContext.snapshotSignalTree(rootPiboSessionId));
4283
- unsubscribe = context.channelContext.subscribeSignalTree(rootPiboSessionId, (patch) => {
4284
- writeJsonSse(controller, "signal_patch", patch, String(patch.toVersion));
4306
+ unsubscribeTree = context.channelContext.subscribeSignalTree(rootPiboSessionId, (patch) => {
4307
+ if (!closed)
4308
+ writeJsonSse(controller, "signal_patch", patch, String(patch.toVersion));
4285
4309
  });
4286
- heartbeat = setInterval(() => writeSseComment(controller, "heartbeat"), 25_000);
4310
+ if (includeStatuses) {
4311
+ writeJsonSse(controller, "signal_status_snapshot", context.channelContext.snapshotSignalStatuses());
4312
+ unsubscribeStatuses = context.channelContext.subscribeSignalStatuses((patch) => {
4313
+ if (closed)
4314
+ return;
4315
+ const statusPatch = compactSignalStatusPatch(patch);
4316
+ writeJsonSse(controller, "signal_status_patch", statusPatch, `${patch.rootPiboSessionId}:${patch.toVersion}`);
4317
+ });
4318
+ }
4319
+ heartbeat = setInterval(() => {
4320
+ if (!closed)
4321
+ writeSseComment(controller, "heartbeat");
4322
+ }, 25_000);
4287
4323
  },
4288
4324
  cancel: () => {
4289
- unsubscribe?.();
4290
- unsubscribe = undefined;
4325
+ closed = true;
4326
+ unsubscribeTree?.();
4327
+ unsubscribeTree = undefined;
4328
+ unsubscribeStatuses?.();
4329
+ unsubscribeStatuses = undefined;
4291
4330
  if (heartbeat)
4292
4331
  clearInterval(heartbeat);
4293
4332
  heartbeat = undefined;
@@ -4691,6 +4730,9 @@ export function createChatWebApp(options = {}) {
4691
4730
  if (customAgentUpdateAffectsRuntime(update)) {
4692
4731
  await requireValidCustomAgentRuntime(previewCustomAgentUpdate(existing, update), context);
4693
4732
  }
4733
+ if (archived === true && !existing.archivedAt) {
4734
+ requireCustomAgentNotTargeted(state, existing, { activeOnly: true });
4735
+ }
4694
4736
  const updated = Object.keys(update).length ? state.agentStore.update(patchAgentId, update) : existing;
4695
4737
  const afterUpdate = requireSharedAgent(updated);
4696
4738
  const agent = archived === undefined ? afterUpdate : state.agentStore.setArchived(patchAgentId, archived);
@@ -4717,8 +4759,16 @@ export function createChatWebApp(options = {}) {
4717
4759
  if (confirmName !== agent.profileName) {
4718
4760
  throw new PiboWebHttpError(`Type "${agent.profileName}" to permanently delete this agent and its sessions.`, 400);
4719
4761
  }
4762
+ requireCustomAgentNotTargeted(state, agent);
4720
4763
  const deletedSessionIds = await deleteSessionsForAgentProfile(state, context, webSession, [agent.profileName, ...agent.profileAliases]);
4721
- state.agentStore.delete(agent.id);
4764
+ try {
4765
+ state.agentStore.delete(agent.id);
4766
+ }
4767
+ catch (error) {
4768
+ if (error instanceof CustomAgentTargetReferenceError)
4769
+ throw new PiboWebHttpError(error.message, 409);
4770
+ throw error;
4771
+ }
4722
4772
  context.channelContext.removeProfile?.(agent.profileName);
4723
4773
  invalidateBootstrapCatalogCache(state);
4724
4774
  return responseJson({ deletedAgentId: agent.id, deletedSessionIds });
@@ -4829,7 +4879,16 @@ export function createChatWebApp(options = {}) {
4829
4879
  const update = createRoomUpdate(existingRoom, body);
4830
4880
  if (update.parentRoomId)
4831
4881
  requireRoom(state, update.parentRoomId, webSession, "admin");
4832
- const room = state.roomService.updateRoom(roomResource.roomId, update);
4882
+ let room;
4883
+ try {
4884
+ room = state.roomService.updateRoom(roomResource.roomId, update);
4885
+ }
4886
+ catch (error) {
4887
+ if (error instanceof PiboRoomHierarchyCycleError) {
4888
+ throw new PiboWebHttpError(error.message, 400);
4889
+ }
4890
+ throw error;
4891
+ }
4833
4892
  if (!room)
4834
4893
  throw new PiboWebHttpError("Room not found", 404);
4835
4894
  return responseJson({ room });