bazilion 0.21.0 → 0.22.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.
Files changed (101) hide show
  1. package/dist/cli.js +25 -6
  2. package/dist/cli.js.map +1 -1
  3. package/dist/daemon.js +1046 -152
  4. package/dist/daemon.js.map +1 -1
  5. package/dist/migrations/0004_image_generation.sql +25 -0
  6. package/dist/web/client/assets/{AgentTabs-BT7RsEUU.js → AgentTabs-CBFT1Qg2.js} +1 -1
  7. package/dist/web/client/assets/{ChatPane-3I0Vsgz1.js → ChatPane-2r2r-Ac6.js} +2 -2
  8. package/dist/web/client/assets/{ConfigPage-hftJBBIY.js → ConfigPage-Cv0KGMX2.js} +1 -1
  9. package/dist/web/client/assets/{ConfirmDialog-gjgxRmxG.js → ConfirmDialog-DEwIcBm4.js} +1 -1
  10. package/dist/web/client/assets/FieldRow-C2ZAwThs.js +1 -0
  11. package/dist/web/client/assets/{ProductionTeamPolicyEditor-D4WcyDGX.js → ProductionTeamPolicyEditor-CziOzJPc.js} +1 -1
  12. package/dist/web/client/assets/{ProfileCommunicationEditor-CgIyV1rY.js → ProfileCommunicationEditor-DRasiT4-.js} +1 -1
  13. package/dist/web/client/assets/{RecoveryState-CbuT_rGW.js → RecoveryState-BZVq08km.js} +1 -1
  14. package/dist/web/client/assets/ResultCard-Dv5E8nX2.js +1 -0
  15. package/dist/web/client/assets/{ResultSourceConversation-CYBczpnZ.js → ResultSourceConversation-DutMGQB2.js} +1 -1
  16. package/dist/web/client/assets/{SectionTabs-t8xkqWIa.js → SectionTabs-mrflsPU-.js} +1 -1
  17. package/dist/web/client/assets/{TeamTabs-BN6P91fO.js → TeamTabs-DMVP5Hce.js} +1 -1
  18. package/dist/web/client/assets/{TemplatesTabs-DwG1CWan.js → TemplatesTabs-PxjxEiJG.js} +1 -1
  19. package/dist/web/client/assets/{UnsavedChangesGuard-fTPP7TCu.js → UnsavedChangesGuard-DfuiWMQ_.js} +1 -1
  20. package/dist/web/client/assets/{_id-Bcqu2cAS.js → _id-AcER9d-z.js} +1 -1
  21. package/dist/web/client/assets/{_id-CZG5wnur.js → _id-BTqFkUlB.js} +1 -1
  22. package/dist/web/client/assets/{_id-Bqk9L9xm.js → _id-Btgd0eQD.js} +1 -1
  23. package/dist/web/client/assets/{_id-DbwNJKQ8.js → _id-CgRuUtaW.js} +1 -1
  24. package/dist/web/client/assets/{_id-Di_SGuwC.js → _id-CrshYgbI.js} +1 -1
  25. package/dist/web/client/assets/{_id-DoW8SZjQ.js → _id-D51zCmQL.js} +1 -1
  26. package/dist/web/client/assets/{_id-DYkghdJm.js → _id-DqfO8lgv.js} +1 -1
  27. package/dist/web/client/assets/{_id-CRG3gXZW.js → _id-danxFImG.js} +1 -1
  28. package/dist/web/client/assets/{activity-vP2HVz4C.js → activity-CMaTYBPw.js} +1 -1
  29. package/dist/web/client/assets/{activity-Bt9WrtwT.js → activity-TilqK2MN.js} +1 -1
  30. package/dist/web/client/assets/{agents-gvU7Aqby.js → agents-D2gE-ZHl.js} +1 -1
  31. package/dist/web/client/assets/{agents-Bo7EfRdf.js → agents-D5_60Do4.js} +1 -1
  32. package/dist/web/client/assets/{agents-DaNXwDyg.js → agents-DPFzFgU2.js} +1 -1
  33. package/dist/web/client/assets/{approvals-DmJ5zwtE.js → approvals-BfoaMnwC.js} +1 -1
  34. package/dist/web/client/assets/{approvals-BOJoboDp.js → approvals-Du7G-YHg.js} +1 -1
  35. package/dist/web/client/assets/{attention-yEG75DvH.js → attention-C11m4NJY.js} +1 -1
  36. package/dist/web/client/assets/{attention-DWPCjYsx.js → attention-Cv18TBIb.js} +1 -1
  37. package/dist/web/client/assets/chevron-right-WaxL25XX.js +1 -0
  38. package/dist/web/client/assets/{config-B8YR3RWJ.js → config-crruyOmj.js} +2 -2
  39. package/dist/web/client/assets/{context-Cqc6E2UY.js → context-JT1dYNoO.js} +1 -1
  40. package/dist/web/client/assets/{inbox-PEvgddwX.js → inbox-DC5XSXiy.js} +1 -1
  41. package/dist/web/client/assets/{inbox-C2B8Re-f.js → inbox-OQ0QyvzA.js} +1 -1
  42. package/dist/web/client/assets/{index-CK_tkx73.js → index-DThtB1z2.js} +2 -2
  43. package/dist/web/client/assets/{learning-C8u7s_fv.js → learning-CeMSJbAY.js} +1 -1
  44. package/dist/web/client/assets/{learning-CTOIJfXI.js → learning-MO7fDBpd.js} +1 -1
  45. package/dist/web/client/assets/{login-32oN5__g.js → login-B1mPI9h5.js} +1 -1
  46. package/dist/web/client/assets/{mcp-BatNZnwC.js → mcp-Bo-E-MdF.js} +1 -1
  47. package/dist/web/client/assets/{mcp-CMdrj5RZ.js → mcp-CmzHMhei.js} +1 -1
  48. package/dist/web/client/assets/{members-CIVp1pgE.js → members-C7bazwZU.js} +1 -1
  49. package/dist/web/client/assets/{members-CdL5g4oy.js → members-sxSJCxkS.js} +1 -1
  50. package/dist/web/client/assets/{memory-DB2R5Zna.js → memory-BiBOuBA1.js} +1 -1
  51. package/dist/web/client/assets/{memory-kGfkKaO9.js → memory-VYCztjts.js} +1 -1
  52. package/dist/web/client/assets/{policy-D6mIMw1q.js → policy-C8SKHMJc.js} +1 -1
  53. package/dist/web/client/assets/{policy-3wgqPeNP.js → policy-CxN-ZrEm.js} +1 -1
  54. package/dist/web/client/assets/{results-Bt-h8qZH.js → results-BI_dzjgu.js} +1 -1
  55. package/dist/web/client/assets/{results-DNv3ByLD.js → results-DnrL5Mvt.js} +1 -1
  56. package/dist/web/client/assets/{review-CT9N-mCa.js → review-CtGjuoBA.js} +1 -1
  57. package/dist/web/client/assets/{review-NchTcTNb.js → review-D_F2VNul.js} +1 -1
  58. package/dist/web/client/assets/{routes-Dsbob2Ux.js → routes-CLcJb0Gu.js} +1 -1
  59. package/dist/web/client/assets/{services-BRUdbA_y.js → services-Ca1LbXwW.js} +1 -1
  60. package/dist/web/client/assets/{services-CkInaMBQ.js → services-D3rWjxvT.js} +1 -1
  61. package/dist/web/client/assets/{skills-By2Mztj4.js → skills-CbaN9DoR.js} +1 -1
  62. package/dist/web/client/assets/{skills-BYlQVmk4.js → skills-xLrt1IKk.js} +1 -1
  63. package/dist/web/client/assets/{teams-Ckkao-PS.js → teams-DagnWLAA.js} +1 -1
  64. package/dist/web/client/assets/{teams-CVAt-A9j.js → teams-DwSzsbr8.js} +1 -1
  65. package/dist/web/client/assets/{teams--rX4Emqg.js → teams-WVfQMDzi.js} +1 -1
  66. package/dist/web/client/assets/{teams-DokMjbwf.js → teams-tpI7S4u0.js} +1 -1
  67. package/dist/web/client/assets/{telegram-HbT_i0ez.js → telegram-hnIzZf3m.js} +1 -1
  68. package/dist/web/client/assets/{templates-ChE1fd0Z.js → templates-dmFNbHkN.js} +1 -1
  69. package/dist/web/client/assets/{tokens-BV8ipZCW.js → tokens-DMbCr1_1.js} +1 -1
  70. package/dist/web/client/assets/{tokens-CBjv3oax.js → tokens-DUx-zUYt.js} +1 -1
  71. package/dist/web/client/assets/{triggers-BhpXkk_u.js → triggers-BwjNuh-V.js} +1 -1
  72. package/dist/web/client/assets/{triggers-Fe-XQRpk.js → triggers-CM4j23G4.js} +1 -1
  73. package/dist/web/client/assets/{verifications-CPV9gl2d.js → verifications-DGVTf-_3.js} +1 -1
  74. package/dist/web/client/assets/{verifications-CRrwQEXg.js → verifications-bgpZuwOC.js} +1 -1
  75. package/dist/web/client/assets/{welcome-DD_q6paM.js → welcome-p8_5r05g.js} +1 -1
  76. package/dist/web/client/assets/{x-DHrC-Hx0.js → x-CGJA1SM6.js} +1 -1
  77. package/dist/web/server/assets/{ChatPane-CLUUTi2r.js → ChatPane-DsDa1E0a.js} +3 -3
  78. package/dist/web/server/assets/{FieldRow-BEFxeckR.js → FieldRow-DPO8x_le.js} +21 -1
  79. package/dist/web/server/assets/{ResultCard-CFjh8884.js → ResultCard-BtVFqdRU.js} +20 -1
  80. package/dist/web/server/assets/{ResultSourceConversation-BoRcXEfg.js → ResultSourceConversation-NKiRGO6_.js} +1 -1
  81. package/dist/web/server/assets/{_id-B-tA4zr0.js → _id-BLHUW0oS.js} +1 -1
  82. package/dist/web/server/assets/{_id-j2iOW-7w.js → _id-BxTsdM7U.js} +3 -3
  83. package/dist/web/server/assets/{_id-4t_AIt1b.js → _id-CAxK6pln.js} +1 -1
  84. package/dist/web/server/assets/{_id-B8EgU2la.js → _id-CmS2d0me.js} +2 -2
  85. package/dist/web/server/assets/{_tanstack-start-manifest_v-D6Cx8dbN.js → _tanstack-start-manifest_v-DsMaFmpx.js} +133 -133
  86. package/dist/web/server/assets/{config-C63Rp2Tc.js → config-DM2DIzMT.js} +1 -1
  87. package/dist/web/server/assets/{config-Cnj8GNk_.js → config-DX3c4Co0.js} +5 -3
  88. package/dist/web/server/assets/{results-m4JaXsRF.js → results-BFPu3tcP.js} +1 -1
  89. package/dist/web/server/assets/{results-BWsxk1aR.js → results-TR7VXLdQ.js} +3 -3
  90. package/dist/web/server/assets/{router-CMMB5oyy.js → router-DlwGPg99.js} +6 -6
  91. package/dist/web/server/assets/{routes-DFAvoScC.js → routes-BGMHt0b0.js} +2 -2
  92. package/dist/web/server/assets/{routes-BrtSbu3l.js → routes-kSjMHwrg.js} +1 -1
  93. package/dist/web/server/assets/{services-W4rO8Lc-.js → services-T8adll3y.js} +14 -6
  94. package/dist/web/server/assets/{services-2f0nAQPX.js → services-UL_2b8PP.js} +1 -1
  95. package/dist/web/server/server.js +2 -2
  96. package/dist/worker.js +208 -2
  97. package/dist/worker.js.map +1 -1
  98. package/package.json +6 -6
  99. package/dist/web/client/assets/FieldRow-VR8Sv-gN.js +0 -1
  100. package/dist/web/client/assets/ResultCard-D1bopCj0.js +0 -1
  101. package/dist/web/client/assets/chevron-right-BxPmmRg9.js +0 -1
package/dist/daemon.js CHANGED
@@ -742,9 +742,9 @@ function floatSafeRemainder(val, step) {
742
742
  return 0;
743
743
  return ratio - roundedRatio;
744
744
  }
745
- function defineLazy(object5, key3, getter) {
745
+ function defineLazy(object6, key3, getter) {
746
746
  let value = void 0;
747
- Object.defineProperty(object5, key3, {
747
+ Object.defineProperty(object6, key3, {
748
748
  get() {
749
749
  if (value === EVALUATING) {
750
750
  return void 0;
@@ -756,7 +756,7 @@ function defineLazy(object5, key3, getter) {
756
756
  return value;
757
757
  },
758
758
  set(v2) {
759
- Object.defineProperty(object5, key3, {
759
+ Object.defineProperty(object6, key3, {
760
760
  value: v2
761
761
  // configurable: true,
762
762
  });
@@ -5251,7 +5251,7 @@ function never(params) {
5251
5251
  function array(element, params) {
5252
5252
  return _array(ZodArray, element, params);
5253
5253
  }
5254
- function object3(shape, params) {
5254
+ function object4(shape, params) {
5255
5255
  const def = {
5256
5256
  type: "object",
5257
5257
  shape: shape ?? {},
@@ -6196,10 +6196,10 @@ var init_types = __esm({
6196
6196
  */
6197
6197
  pollInterval: number2().optional()
6198
6198
  });
6199
- TaskMetadataSchema = object3({
6199
+ TaskMetadataSchema = object4({
6200
6200
  ttl: number2().optional()
6201
6201
  });
6202
- RelatedTaskMetadataSchema = object3({
6202
+ RelatedTaskMetadataSchema = object4({
6203
6203
  taskId: string3()
6204
6204
  });
6205
6205
  RequestMetaSchema = looseObject({
@@ -6212,7 +6212,7 @@ var init_types = __esm({
6212
6212
  */
6213
6213
  [RELATED_TASK_META_KEY]: RelatedTaskMetadataSchema.optional()
6214
6214
  });
6215
- BaseRequestParamsSchema = object3({
6215
+ BaseRequestParamsSchema = object4({
6216
6216
  /**
6217
6217
  * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.
6218
6218
  */
@@ -6230,18 +6230,18 @@ var init_types = __esm({
6230
6230
  task: TaskMetadataSchema.optional()
6231
6231
  });
6232
6232
  isTaskAugmentedRequestParams = (value) => TaskAugmentedRequestParamsSchema.safeParse(value).success;
6233
- RequestSchema = object3({
6233
+ RequestSchema = object4({
6234
6234
  method: string3(),
6235
6235
  params: BaseRequestParamsSchema.loose().optional()
6236
6236
  });
6237
- NotificationsParamsSchema = object3({
6237
+ NotificationsParamsSchema = object4({
6238
6238
  /**
6239
6239
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
6240
6240
  * for notes on _meta usage.
6241
6241
  */
6242
6242
  _meta: RequestMetaSchema.optional()
6243
6243
  });
6244
- NotificationSchema = object3({
6244
+ NotificationSchema = object4({
6245
6245
  method: string3(),
6246
6246
  params: NotificationsParamsSchema.loose().optional()
6247
6247
  });
@@ -6253,18 +6253,18 @@ var init_types = __esm({
6253
6253
  _meta: RequestMetaSchema.optional()
6254
6254
  });
6255
6255
  RequestIdSchema = union([string3(), number2().int()]);
6256
- JSONRPCRequestSchema = object3({
6256
+ JSONRPCRequestSchema = object4({
6257
6257
  jsonrpc: literal(JSONRPC_VERSION),
6258
6258
  id: RequestIdSchema,
6259
6259
  ...RequestSchema.shape
6260
6260
  }).strict();
6261
6261
  isJSONRPCRequest = (value) => JSONRPCRequestSchema.safeParse(value).success;
6262
- JSONRPCNotificationSchema = object3({
6262
+ JSONRPCNotificationSchema = object4({
6263
6263
  jsonrpc: literal(JSONRPC_VERSION),
6264
6264
  ...NotificationSchema.shape
6265
6265
  }).strict();
6266
6266
  isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(value).success;
6267
- JSONRPCResultResponseSchema = object3({
6267
+ JSONRPCResultResponseSchema = object4({
6268
6268
  jsonrpc: literal(JSONRPC_VERSION),
6269
6269
  id: RequestIdSchema,
6270
6270
  result: ResultSchema
@@ -6280,10 +6280,10 @@ var init_types = __esm({
6280
6280
  ErrorCode2[ErrorCode2["InternalError"] = -32603] = "InternalError";
6281
6281
  ErrorCode2[ErrorCode2["UrlElicitationRequired"] = -32042] = "UrlElicitationRequired";
6282
6282
  })(ErrorCode || (ErrorCode = {}));
6283
- JSONRPCErrorResponseSchema = object3({
6283
+ JSONRPCErrorResponseSchema = object4({
6284
6284
  jsonrpc: literal(JSONRPC_VERSION),
6285
6285
  id: RequestIdSchema.optional(),
6286
- error: object3({
6286
+ error: object4({
6287
6287
  /**
6288
6288
  * The error type that occurred.
6289
6289
  */
@@ -6323,7 +6323,7 @@ var init_types = __esm({
6323
6323
  method: literal("notifications/cancelled"),
6324
6324
  params: CancelledNotificationParamsSchema
6325
6325
  });
6326
- IconSchema = object3({
6326
+ IconSchema = object4({
6327
6327
  /**
6328
6328
  * URL or data URI for the icon.
6329
6329
  */
@@ -6348,7 +6348,7 @@ var init_types = __esm({
6348
6348
  */
6349
6349
  theme: _enum(["light", "dark"]).optional()
6350
6350
  });
6351
- IconsSchema = object3({
6351
+ IconsSchema = object4({
6352
6352
  /**
6353
6353
  * Optional set of sized icons that the client can display in a user interface.
6354
6354
  *
@@ -6362,7 +6362,7 @@ var init_types = __esm({
6362
6362
  */
6363
6363
  icons: array(IconSchema).optional()
6364
6364
  });
6365
- BaseMetadataSchema = object3({
6365
+ BaseMetadataSchema = object4({
6366
6366
  /** Intended for programmatic or logical use, but used as a display name in past specs or fallback */
6367
6367
  name: string3(),
6368
6368
  /**
@@ -6392,7 +6392,7 @@ var init_types = __esm({
6392
6392
  */
6393
6393
  description: string3().optional()
6394
6394
  });
6395
- FormElicitationCapabilitySchema = intersection(object3({
6395
+ FormElicitationCapabilitySchema = intersection(object4({
6396
6396
  applyDefaults: boolean2().optional()
6397
6397
  }), record2(string3(), unknown()));
6398
6398
  ElicitationCapabilitySchema = preprocess((value) => {
@@ -6402,7 +6402,7 @@ var init_types = __esm({
6402
6402
  }
6403
6403
  }
6404
6404
  return value;
6405
- }, intersection(object3({
6405
+ }, intersection(object4({
6406
6406
  form: FormElicitationCapabilitySchema.optional(),
6407
6407
  url: AssertObjectSchema.optional()
6408
6408
  }), record2(string3(), unknown()).optional()));
@@ -6454,7 +6454,7 @@ var init_types = __esm({
6454
6454
  }).optional()
6455
6455
  }).optional()
6456
6456
  });
6457
- ClientCapabilitiesSchema = object3({
6457
+ ClientCapabilitiesSchema = object4({
6458
6458
  /**
6459
6459
  * Experimental, non-standard capabilities that the client supports.
6460
6460
  */
@@ -6462,7 +6462,7 @@ var init_types = __esm({
6462
6462
  /**
6463
6463
  * Present if the client supports sampling from an LLM.
6464
6464
  */
6465
- sampling: object3({
6465
+ sampling: object4({
6466
6466
  /**
6467
6467
  * Present if the client supports context inclusion via includeContext parameter.
6468
6468
  * If not declared, servers SHOULD only use `includeContext: "none"` (or omit it).
@@ -6480,7 +6480,7 @@ var init_types = __esm({
6480
6480
  /**
6481
6481
  * Present if the client supports listing roots.
6482
6482
  */
6483
- roots: object3({
6483
+ roots: object4({
6484
6484
  /**
6485
6485
  * Whether the client supports issuing notifications for changes to the roots list.
6486
6486
  */
@@ -6507,7 +6507,7 @@ var init_types = __esm({
6507
6507
  method: literal("initialize"),
6508
6508
  params: InitializeRequestParamsSchema
6509
6509
  });
6510
- ServerCapabilitiesSchema = object3({
6510
+ ServerCapabilitiesSchema = object4({
6511
6511
  /**
6512
6512
  * Experimental, non-standard capabilities that the server supports.
6513
6513
  */
@@ -6523,7 +6523,7 @@ var init_types = __esm({
6523
6523
  /**
6524
6524
  * Present if the server offers any prompt templates.
6525
6525
  */
6526
- prompts: object3({
6526
+ prompts: object4({
6527
6527
  /**
6528
6528
  * Whether this server supports issuing notifications for changes to the prompt list.
6529
6529
  */
@@ -6532,7 +6532,7 @@ var init_types = __esm({
6532
6532
  /**
6533
6533
  * Present if the server offers any resources to read.
6534
6534
  */
6535
- resources: object3({
6535
+ resources: object4({
6536
6536
  /**
6537
6537
  * Whether this server supports clients subscribing to resource updates.
6538
6538
  */
@@ -6545,7 +6545,7 @@ var init_types = __esm({
6545
6545
  /**
6546
6546
  * Present if the server offers any tools to call.
6547
6547
  */
6548
- tools: object3({
6548
+ tools: object4({
6549
6549
  /**
6550
6550
  * Whether this server supports issuing notifications for changes to the tool list.
6551
6551
  */
@@ -6583,7 +6583,7 @@ var init_types = __esm({
6583
6583
  method: literal("ping"),
6584
6584
  params: BaseRequestParamsSchema.optional()
6585
6585
  });
6586
- ProgressSchema = object3({
6586
+ ProgressSchema = object4({
6587
6587
  /**
6588
6588
  * The progress thus far. This should increase every time progress is made, even if the total is unknown.
6589
6589
  */
@@ -6597,7 +6597,7 @@ var init_types = __esm({
6597
6597
  */
6598
6598
  message: optional(string3())
6599
6599
  });
6600
- ProgressNotificationParamsSchema = object3({
6600
+ ProgressNotificationParamsSchema = object4({
6601
6601
  ...NotificationsParamsSchema.shape,
6602
6602
  ...ProgressSchema.shape,
6603
6603
  /**
@@ -6627,7 +6627,7 @@ var init_types = __esm({
6627
6627
  nextCursor: CursorSchema.optional()
6628
6628
  });
6629
6629
  TaskStatusSchema = _enum(["working", "input_required", "completed", "failed", "cancelled"]);
6630
- TaskSchema = object3({
6630
+ TaskSchema = object4({
6631
6631
  taskId: string3(),
6632
6632
  status: TaskStatusSchema,
6633
6633
  /**
@@ -6684,7 +6684,7 @@ var init_types = __esm({
6684
6684
  })
6685
6685
  });
6686
6686
  CancelTaskResultSchema = ResultSchema.merge(TaskSchema);
6687
- ResourceContentsSchema = object3({
6687
+ ResourceContentsSchema = object4({
6688
6688
  /**
6689
6689
  * The URI of this resource.
6690
6690
  */
@@ -6720,7 +6720,7 @@ var init_types = __esm({
6720
6720
  blob: Base64Schema
6721
6721
  });
6722
6722
  RoleSchema = _enum(["user", "assistant"]);
6723
- AnnotationsSchema = object3({
6723
+ AnnotationsSchema = object4({
6724
6724
  /**
6725
6725
  * Intended audience(s) for the resource.
6726
6726
  */
@@ -6734,7 +6734,7 @@ var init_types = __esm({
6734
6734
  */
6735
6735
  lastModified: iso_exports.datetime({ offset: true }).optional()
6736
6736
  });
6737
- ResourceSchema = object3({
6737
+ ResourceSchema = object4({
6738
6738
  ...BaseMetadataSchema.shape,
6739
6739
  ...IconsSchema.shape,
6740
6740
  /**
@@ -6767,7 +6767,7 @@ var init_types = __esm({
6767
6767
  */
6768
6768
  _meta: optional(looseObject({}))
6769
6769
  });
6770
- ResourceTemplateSchema = object3({
6770
+ ResourceTemplateSchema = object4({
6771
6771
  ...BaseMetadataSchema.shape,
6772
6772
  ...IconsSchema.shape,
6773
6773
  /**
@@ -6846,7 +6846,7 @@ var init_types = __esm({
6846
6846
  method: literal("notifications/resources/updated"),
6847
6847
  params: ResourceUpdatedNotificationParamsSchema
6848
6848
  });
6849
- PromptArgumentSchema = object3({
6849
+ PromptArgumentSchema = object4({
6850
6850
  /**
6851
6851
  * The name of the argument.
6852
6852
  */
@@ -6860,7 +6860,7 @@ var init_types = __esm({
6860
6860
  */
6861
6861
  required: optional(boolean2())
6862
6862
  });
6863
- PromptSchema = object3({
6863
+ PromptSchema = object4({
6864
6864
  ...BaseMetadataSchema.shape,
6865
6865
  ...IconsSchema.shape,
6866
6866
  /**
@@ -6897,7 +6897,7 @@ var init_types = __esm({
6897
6897
  method: literal("prompts/get"),
6898
6898
  params: GetPromptRequestParamsSchema
6899
6899
  });
6900
- TextContentSchema = object3({
6900
+ TextContentSchema = object4({
6901
6901
  type: literal("text"),
6902
6902
  /**
6903
6903
  * The text content of the message.
@@ -6913,7 +6913,7 @@ var init_types = __esm({
6913
6913
  */
6914
6914
  _meta: record2(string3(), unknown()).optional()
6915
6915
  });
6916
- ImageContentSchema = object3({
6916
+ ImageContentSchema = object4({
6917
6917
  type: literal("image"),
6918
6918
  /**
6919
6919
  * The base64-encoded image data.
@@ -6933,7 +6933,7 @@ var init_types = __esm({
6933
6933
  */
6934
6934
  _meta: record2(string3(), unknown()).optional()
6935
6935
  });
6936
- AudioContentSchema = object3({
6936
+ AudioContentSchema = object4({
6937
6937
  type: literal("audio"),
6938
6938
  /**
6939
6939
  * The base64-encoded audio data.
@@ -6953,7 +6953,7 @@ var init_types = __esm({
6953
6953
  */
6954
6954
  _meta: record2(string3(), unknown()).optional()
6955
6955
  });
6956
- ToolUseContentSchema = object3({
6956
+ ToolUseContentSchema = object4({
6957
6957
  type: literal("tool_use"),
6958
6958
  /**
6959
6959
  * The name of the tool to invoke.
@@ -6976,7 +6976,7 @@ var init_types = __esm({
6976
6976
  */
6977
6977
  _meta: record2(string3(), unknown()).optional()
6978
6978
  });
6979
- EmbeddedResourceSchema = object3({
6979
+ EmbeddedResourceSchema = object4({
6980
6980
  type: literal("resource"),
6981
6981
  resource: union([TextResourceContentsSchema, BlobResourceContentsSchema]),
6982
6982
  /**
@@ -6999,7 +6999,7 @@ var init_types = __esm({
6999
6999
  ResourceLinkSchema,
7000
7000
  EmbeddedResourceSchema
7001
7001
  ]);
7002
- PromptMessageSchema = object3({
7002
+ PromptMessageSchema = object4({
7003
7003
  role: RoleSchema,
7004
7004
  content: ContentBlockSchema
7005
7005
  });
@@ -7014,7 +7014,7 @@ var init_types = __esm({
7014
7014
  method: literal("notifications/prompts/list_changed"),
7015
7015
  params: NotificationsParamsSchema.optional()
7016
7016
  });
7017
- ToolAnnotationsSchema = object3({
7017
+ ToolAnnotationsSchema = object4({
7018
7018
  /**
7019
7019
  * A human-readable title for the tool.
7020
7020
  */
@@ -7053,7 +7053,7 @@ var init_types = __esm({
7053
7053
  */
7054
7054
  openWorldHint: boolean2().optional()
7055
7055
  });
7056
- ToolExecutionSchema = object3({
7056
+ ToolExecutionSchema = object4({
7057
7057
  /**
7058
7058
  * Indicates the tool's preference for task-augmented execution.
7059
7059
  * - "required": Clients MUST invoke the tool as a task
@@ -7064,7 +7064,7 @@ var init_types = __esm({
7064
7064
  */
7065
7065
  taskSupport: _enum(["required", "optional", "forbidden"]).optional()
7066
7066
  });
7067
- ToolSchema = object3({
7067
+ ToolSchema = object4({
7068
7068
  ...BaseMetadataSchema.shape,
7069
7069
  ...IconsSchema.shape,
7070
7070
  /**
@@ -7075,7 +7075,7 @@ var init_types = __esm({
7075
7075
  * A JSON Schema 2020-12 object defining the expected parameters for the tool.
7076
7076
  * Must have type: 'object' at the root level per MCP spec.
7077
7077
  */
7078
- inputSchema: object3({
7078
+ inputSchema: object4({
7079
7079
  type: literal("object"),
7080
7080
  properties: record2(string3(), AssertObjectSchema).optional(),
7081
7081
  required: array(string3()).optional()
@@ -7085,7 +7085,7 @@ var init_types = __esm({
7085
7085
  * returned in the structuredContent field of a CallToolResult.
7086
7086
  * Must have type: 'object' at the root level per MCP spec.
7087
7087
  */
7088
- outputSchema: object3({
7088
+ outputSchema: object4({
7089
7089
  type: literal("object"),
7090
7090
  properties: record2(string3(), AssertObjectSchema).optional(),
7091
7091
  required: array(string3()).optional()
@@ -7161,7 +7161,7 @@ var init_types = __esm({
7161
7161
  method: literal("notifications/tools/list_changed"),
7162
7162
  params: NotificationsParamsSchema.optional()
7163
7163
  });
7164
- ListChangedOptionsBaseSchema = object3({
7164
+ ListChangedOptionsBaseSchema = object4({
7165
7165
  /**
7166
7166
  * If true, the list will be refreshed automatically when a list changed notification is received.
7167
7167
  * The callback will be called with the updated list.
@@ -7210,13 +7210,13 @@ var init_types = __esm({
7210
7210
  method: literal("notifications/message"),
7211
7211
  params: LoggingMessageNotificationParamsSchema
7212
7212
  });
7213
- ModelHintSchema = object3({
7213
+ ModelHintSchema = object4({
7214
7214
  /**
7215
7215
  * A hint for a model name.
7216
7216
  */
7217
7217
  name: string3().optional()
7218
7218
  });
7219
- ModelPreferencesSchema = object3({
7219
+ ModelPreferencesSchema = object4({
7220
7220
  /**
7221
7221
  * Optional hints to use for model selection.
7222
7222
  */
@@ -7234,7 +7234,7 @@ var init_types = __esm({
7234
7234
  */
7235
7235
  intelligencePriority: number2().min(0).max(1).optional()
7236
7236
  });
7237
- ToolChoiceSchema = object3({
7237
+ ToolChoiceSchema = object4({
7238
7238
  /**
7239
7239
  * Controls when tools are used:
7240
7240
  * - "auto": Model decides whether to use tools (default)
@@ -7243,11 +7243,11 @@ var init_types = __esm({
7243
7243
  */
7244
7244
  mode: _enum(["auto", "required", "none"]).optional()
7245
7245
  });
7246
- ToolResultContentSchema = object3({
7246
+ ToolResultContentSchema = object4({
7247
7247
  type: literal("tool_result"),
7248
7248
  toolUseId: string3().describe("The unique identifier for the corresponding tool call."),
7249
7249
  content: array(ContentBlockSchema).default([]),
7250
- structuredContent: object3({}).loose().optional(),
7250
+ structuredContent: object4({}).loose().optional(),
7251
7251
  isError: boolean2().optional(),
7252
7252
  /**
7253
7253
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
@@ -7263,7 +7263,7 @@ var init_types = __esm({
7263
7263
  ToolUseContentSchema,
7264
7264
  ToolResultContentSchema
7265
7265
  ]);
7266
- SamplingMessageSchema = object3({
7266
+ SamplingMessageSchema = object4({
7267
7267
  role: RoleSchema,
7268
7268
  content: union([SamplingMessageContentBlockSchema, array(SamplingMessageContentBlockSchema)]),
7269
7269
  /**
@@ -7363,13 +7363,13 @@ var init_types = __esm({
7363
7363
  */
7364
7364
  content: union([SamplingMessageContentBlockSchema, array(SamplingMessageContentBlockSchema)])
7365
7365
  });
7366
- BooleanSchemaSchema = object3({
7366
+ BooleanSchemaSchema = object4({
7367
7367
  type: literal("boolean"),
7368
7368
  title: string3().optional(),
7369
7369
  description: string3().optional(),
7370
7370
  default: boolean2().optional()
7371
7371
  });
7372
- StringSchemaSchema = object3({
7372
+ StringSchemaSchema = object4({
7373
7373
  type: literal("string"),
7374
7374
  title: string3().optional(),
7375
7375
  description: string3().optional(),
@@ -7378,7 +7378,7 @@ var init_types = __esm({
7378
7378
  format: _enum(["email", "uri", "date", "date-time"]).optional(),
7379
7379
  default: string3().optional()
7380
7380
  });
7381
- NumberSchemaSchema = object3({
7381
+ NumberSchemaSchema = object4({
7382
7382
  type: _enum(["number", "integer"]),
7383
7383
  title: string3().optional(),
7384
7384
  description: string3().optional(),
@@ -7386,24 +7386,24 @@ var init_types = __esm({
7386
7386
  maximum: number2().optional(),
7387
7387
  default: number2().optional()
7388
7388
  });
7389
- UntitledSingleSelectEnumSchemaSchema = object3({
7389
+ UntitledSingleSelectEnumSchemaSchema = object4({
7390
7390
  type: literal("string"),
7391
7391
  title: string3().optional(),
7392
7392
  description: string3().optional(),
7393
7393
  enum: array(string3()),
7394
7394
  default: string3().optional()
7395
7395
  });
7396
- TitledSingleSelectEnumSchemaSchema = object3({
7396
+ TitledSingleSelectEnumSchemaSchema = object4({
7397
7397
  type: literal("string"),
7398
7398
  title: string3().optional(),
7399
7399
  description: string3().optional(),
7400
- oneOf: array(object3({
7400
+ oneOf: array(object4({
7401
7401
  const: string3(),
7402
7402
  title: string3()
7403
7403
  })),
7404
7404
  default: string3().optional()
7405
7405
  });
7406
- LegacyTitledEnumSchemaSchema = object3({
7406
+ LegacyTitledEnumSchemaSchema = object4({
7407
7407
  type: literal("string"),
7408
7408
  title: string3().optional(),
7409
7409
  description: string3().optional(),
@@ -7412,26 +7412,26 @@ var init_types = __esm({
7412
7412
  default: string3().optional()
7413
7413
  });
7414
7414
  SingleSelectEnumSchemaSchema = union([UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema]);
7415
- UntitledMultiSelectEnumSchemaSchema = object3({
7415
+ UntitledMultiSelectEnumSchemaSchema = object4({
7416
7416
  type: literal("array"),
7417
7417
  title: string3().optional(),
7418
7418
  description: string3().optional(),
7419
7419
  minItems: number2().optional(),
7420
7420
  maxItems: number2().optional(),
7421
- items: object3({
7421
+ items: object4({
7422
7422
  type: literal("string"),
7423
7423
  enum: array(string3())
7424
7424
  }),
7425
7425
  default: array(string3()).optional()
7426
7426
  });
7427
- TitledMultiSelectEnumSchemaSchema = object3({
7427
+ TitledMultiSelectEnumSchemaSchema = object4({
7428
7428
  type: literal("array"),
7429
7429
  title: string3().optional(),
7430
7430
  description: string3().optional(),
7431
7431
  minItems: number2().optional(),
7432
7432
  maxItems: number2().optional(),
7433
- items: object3({
7434
- anyOf: array(object3({
7433
+ items: object4({
7434
+ anyOf: array(object4({
7435
7435
  const: string3(),
7436
7436
  title: string3()
7437
7437
  }))
@@ -7456,7 +7456,7 @@ var init_types = __esm({
7456
7456
  * A restricted subset of JSON Schema.
7457
7457
  * Only top-level properties are allowed, without nesting.
7458
7458
  */
7459
- requestedSchema: object3({
7459
+ requestedSchema: object4({
7460
7460
  type: literal("object"),
7461
7461
  properties: record2(string3(), PrimitiveSchemaDefinitionSchema),
7462
7462
  required: array(string3()).optional()
@@ -7512,14 +7512,14 @@ var init_types = __esm({
7512
7512
  */
7513
7513
  content: preprocess((val) => val === null ? void 0 : val, record2(string3(), union([string3(), number2(), boolean2(), array(string3())])).optional())
7514
7514
  });
7515
- ResourceTemplateReferenceSchema = object3({
7515
+ ResourceTemplateReferenceSchema = object4({
7516
7516
  type: literal("ref/resource"),
7517
7517
  /**
7518
7518
  * The URI or URI template of the resource.
7519
7519
  */
7520
7520
  uri: string3()
7521
7521
  });
7522
- PromptReferenceSchema = object3({
7522
+ PromptReferenceSchema = object4({
7523
7523
  type: literal("ref/prompt"),
7524
7524
  /**
7525
7525
  * The name of the prompt or prompt template
@@ -7531,7 +7531,7 @@ var init_types = __esm({
7531
7531
  /**
7532
7532
  * The argument's information
7533
7533
  */
7534
- argument: object3({
7534
+ argument: object4({
7535
7535
  /**
7536
7536
  * The name of the argument
7537
7537
  */
@@ -7541,7 +7541,7 @@ var init_types = __esm({
7541
7541
  */
7542
7542
  value: string3()
7543
7543
  }),
7544
- context: object3({
7544
+ context: object4({
7545
7545
  /**
7546
7546
  * Previously-resolved variables in a URI template or prompt.
7547
7547
  */
@@ -7568,7 +7568,7 @@ var init_types = __esm({
7568
7568
  hasMore: optional(boolean2())
7569
7569
  })
7570
7570
  });
7571
- RootSchema = object3({
7571
+ RootSchema = object4({
7572
7572
  /**
7573
7573
  * The URI identifying the root. This *must* start with file:// for now.
7574
7574
  */
@@ -8089,13 +8089,13 @@ var init_auth = __esm({
8089
8089
  op_tos_uri: SafeUrlSchema.optional(),
8090
8090
  client_id_metadata_document_supported: boolean2().optional()
8091
8091
  });
8092
- OpenIdProviderDiscoveryMetadataSchema = object3({
8092
+ OpenIdProviderDiscoveryMetadataSchema = object4({
8093
8093
  ...OpenIdProviderMetadataSchema.shape,
8094
8094
  ...OAuthMetadataSchema.pick({
8095
8095
  code_challenge_methods_supported: true
8096
8096
  }).shape
8097
8097
  });
8098
- OAuthTokensSchema = object3({
8098
+ OAuthTokensSchema = object4({
8099
8099
  access_token: string3(),
8100
8100
  id_token: string3().optional(),
8101
8101
  // Optional for OAuth 2.1, but necessary in OpenID Connect
@@ -8104,13 +8104,13 @@ var init_auth = __esm({
8104
8104
  scope: string3().optional(),
8105
8105
  refresh_token: string3().optional()
8106
8106
  }).strip();
8107
- OAuthErrorResponseSchema = object3({
8107
+ OAuthErrorResponseSchema = object4({
8108
8108
  error: string3(),
8109
8109
  error_description: string3().optional(),
8110
8110
  error_uri: string3().optional()
8111
8111
  });
8112
8112
  OptionalSafeUrlSchema = SafeUrlSchema.optional().or(literal("").transform(() => void 0));
8113
- OAuthClientMetadataSchema = object3({
8113
+ OAuthClientMetadataSchema = object4({
8114
8114
  redirect_uris: array(SafeUrlSchema),
8115
8115
  token_endpoint_auth_method: string3().optional(),
8116
8116
  grant_types: array(string3()).optional(),
@@ -8128,18 +8128,18 @@ var init_auth = __esm({
8128
8128
  software_version: string3().optional(),
8129
8129
  software_statement: string3().optional()
8130
8130
  }).strip();
8131
- OAuthClientInformationSchema = object3({
8131
+ OAuthClientInformationSchema = object4({
8132
8132
  client_id: string3(),
8133
8133
  client_secret: string3().optional(),
8134
8134
  client_id_issued_at: number2().optional(),
8135
8135
  client_secret_expires_at: number2().optional()
8136
8136
  }).strip();
8137
8137
  OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema);
8138
- OAuthClientRegistrationErrorSchema = object3({
8138
+ OAuthClientRegistrationErrorSchema = object4({
8139
8139
  error: string3(),
8140
8140
  error_description: string3().optional()
8141
8141
  }).strip();
8142
- OAuthTokenRevocationRequestSchema = object3({
8142
+ OAuthTokenRevocationRequestSchema = object4({
8143
8143
  token: string3(),
8144
8144
  token_type_hint: string3().optional()
8145
8145
  }).strip();
@@ -22318,6 +22318,85 @@ function finishDelivery(db, id, ok, actor, error2, now = Date.now()) {
22318
22318
  })();
22319
22319
  }
22320
22320
 
22321
+ // ../daemon/src/core/image-generation-config.ts
22322
+ var OPENROUTER_IMAGE_MODELS = [
22323
+ "google/gemini-3.1-flash-image",
22324
+ "openai/gpt-image-2"
22325
+ ];
22326
+ var IMAGE_MODELS = [
22327
+ ...OPENROUTER_IMAGE_MODELS,
22328
+ "openai:gpt-image-2",
22329
+ "openai-codex:gpt-image-2"
22330
+ ];
22331
+ var IMAGE_MODEL_CHOICES = ["auto", ...IMAGE_MODELS];
22332
+ function imageTurnEnv(env, chatModel) {
22333
+ const copy = { ...env };
22334
+ if (!chatModel.startsWith("openrouter:")) delete copy.OPENROUTER_API_KEY;
22335
+ if (!chatModel.startsWith("openai:")) delete copy.OPENAI_API_KEY;
22336
+ return copy;
22337
+ }
22338
+ function imageGenerationConfig(env, codexConnected = false, text3) {
22339
+ if (env.BAZILION_IMAGE_GENERATION !== "on") {
22340
+ return { ready: false, status: "Image generation is off." };
22341
+ }
22342
+ let model = env.BAZILION_IMAGE_MODEL || "auto";
22343
+ const automatic = model === "auto";
22344
+ if (automatic) {
22345
+ const enabled = ["openai", "openai-codex"].filter(
22346
+ (id) => text3?.enabledProviders.has(id)
22347
+ );
22348
+ const chatProvider = text3?.chatModel?.split(":")[0];
22349
+ let provider2;
22350
+ if (chatProvider === "openai" || chatProvider === "openai-codex") {
22351
+ if (!enabled.includes(chatProvider)) {
22352
+ return {
22353
+ ready: false,
22354
+ status: "Automatic images require the Agent\u2019s OpenAI/ChatGPT text provider to be enabled. No switch to another billing route."
22355
+ };
22356
+ }
22357
+ provider2 = chatProvider;
22358
+ } else if (enabled.length === 1 && enabled[0]) {
22359
+ provider2 = enabled[0];
22360
+ } else {
22361
+ return {
22362
+ ready: false,
22363
+ status: enabled.length === 0 ? "Automatic images: enable OpenAI API key or ChatGPT/Codex for text first. Stored credentials alone do not enable a route; OpenRouter requires an explicit image choice." : "Automatic images: both OpenAI text providers are enabled. OpenAI/ChatGPT Agents follow their own text provider; other Agents require an explicit image route. No credential fallback."
22364
+ };
22365
+ }
22366
+ model = `${provider2}:gpt-image-2`;
22367
+ }
22368
+ const selectionNote = automatic ? " Automatic selection follows enabled text providers, never provider failures." : "";
22369
+ if (!IMAGE_MODELS.some((id) => id === model)) {
22370
+ return { ready: false, status: "Select a supported image model before generating images." };
22371
+ }
22372
+ if (model === "openai-codex:gpt-image-2") {
22373
+ return codexConnected ? {
22374
+ ready: true,
22375
+ model,
22376
+ provider: "openai-codex",
22377
+ status: "Ready: gpt-image-2 via ChatGPT/Codex login (subscription limits apply; image entitlement is not yet tested). No API-key fallback." + selectionNote
22378
+ } : {
22379
+ ready: false,
22380
+ status: "Connect ChatGPT on /config or run bazilion auth openai login. Image access depends on your account; no API-key fallback."
22381
+ };
22382
+ }
22383
+ const provider = model === "openai:gpt-image-2" ? "openai" : "openrouter";
22384
+ const key3 = provider === "openai" ? "OPENAI_API_KEY" : "OPENROUTER_API_KEY";
22385
+ const apiKey = env[key3]?.trim();
22386
+ if (!apiKey)
22387
+ return {
22388
+ ready: false,
22389
+ status: `Set ${key3} in the ${provider === "openai" ? "OpenAI" : "OpenRouter"} provider settings. No credential fallback.`
22390
+ };
22391
+ return {
22392
+ ready: true,
22393
+ model,
22394
+ provider,
22395
+ apiKey,
22396
+ status: `Ready: ${model} via ${provider === "openai" ? "OpenAI API key" : "OpenRouter"} (paid API requests; account access is not yet tested).${selectionNote}`
22397
+ };
22398
+ }
22399
+
22321
22400
  // ../daemon/src/core/services.ts
22322
22401
  var SERVICES = [
22323
22402
  // --- LLM providers (configured via API keys / URLs) ---
@@ -22583,6 +22662,20 @@ var SERVICES = [
22583
22662
  hint: "GLM coding endpoint \xB7 open.bigmodel.cn",
22584
22663
  fields: [{ envVar: "ZAI_CODING_CN_API_KEY", kind: "secret", label: "API key" }]
22585
22664
  },
22665
+ {
22666
+ id: "meta",
22667
+ displayName: "Meta",
22668
+ category: "provider",
22669
+ hint: "Meta model API \xB7 api.meta.ai",
22670
+ fields: [{ envVar: "META_API_KEY", kind: "secret", label: "API key" }]
22671
+ },
22672
+ {
22673
+ id: "radius",
22674
+ displayName: "Radius",
22675
+ category: "provider",
22676
+ hint: "Radius gateway \xB7 radius.pi.dev",
22677
+ fields: [{ envVar: "RADIUS_API_KEY", kind: "secret", label: "API key" }]
22678
+ },
22586
22679
  {
22587
22680
  id: "huggingface",
22588
22681
  displayName: "Hugging Face",
@@ -22707,6 +22800,36 @@ var SERVICES = [
22707
22800
  ]
22708
22801
  },
22709
22802
  // --- Ancillary services (web search, etc) ---
22803
+ {
22804
+ id: "image-generation",
22805
+ displayName: "Image generation",
22806
+ category: "service",
22807
+ team: "Content tools",
22808
+ hint: "Automatic (default) follows your enabled OpenAI text providers: API key \u2192 separate API billing; ChatGPT/Codex login \u2192 subscription usage. If both are enabled, OpenAI/ChatGPT Agents use their own text provider; other Agents need an explicit image choice. Saved credentials alone never select a route. OpenRouter is explicit only. Provider failures never switch billing routes. Image generation still requires the separate on switch. Four requests/turn, one in flight/home; environment variables override saved settings.",
22809
+ fields: [
22810
+ {
22811
+ envVar: "BAZILION_IMAGE_MODEL",
22812
+ kind: "config",
22813
+ label: "Default image route / model",
22814
+ options: IMAGE_MODEL_CHOICES,
22815
+ optionLabels: {
22816
+ auto: "Automatic \xB7 follow enabled OpenAI text providers",
22817
+ "google/gemini-3.1-flash-image": "OpenRouter \xB7 Gemini 3.1 Flash Image",
22818
+ "openai/gpt-image-2": "OpenRouter \xB7 GPT Image 2",
22819
+ "openai:gpt-image-2": "OpenAI API key \xB7 GPT Image 2",
22820
+ "openai-codex:gpt-image-2": "ChatGPT/Codex login \xB7 GPT Image 2 (requested)"
22821
+ },
22822
+ description: "Unset or Automatic follows enabled text providers. Explicit selections override automatic routing. API-key routes incur API charges; ChatGPT image entitlement is account-dependent and not tested by saving settings."
22823
+ },
22824
+ {
22825
+ envVar: "BAZILION_IMAGE_GENERATION",
22826
+ kind: "config",
22827
+ label: "Image generation",
22828
+ options: ["off", "on"],
22829
+ description: "Off by default. Enabling permits image requests (API charges or subscription usage) from normal Agent turns, including background turns."
22830
+ }
22831
+ ]
22832
+ },
22710
22833
  {
22711
22834
  id: "firecrawl",
22712
22835
  displayName: "Firecrawl",
@@ -23725,6 +23848,15 @@ var REASONING_LEVELS = [
23725
23848
  var DEVICE_TOKEN_SCOPES = ["read", "write", "approvals", "admin"];
23726
23849
  var ALL_DEVICE_TOKEN_SCOPES = DEVICE_TOKEN_SCOPES;
23727
23850
 
23851
+ // ../../packages/api-types/src/image-generation.ts
23852
+ function imageGenerationRouteLabel(model) {
23853
+ if (model === "openai:gpt-image-2") return "OpenAI API key";
23854
+ if (model === "openai-codex:gpt-image-2") return "ChatGPT/Codex login";
23855
+ if (model === "google/gemini-3.1-flash-image" || model === "openai/gpt-image-2")
23856
+ return "OpenRouter";
23857
+ return "Unknown image route";
23858
+ }
23859
+
23728
23860
  // ../../packages/api-types/src/git-review.ts
23729
23861
  var REVIEW_LIMITS = {
23730
23862
  files: 1e3,
@@ -27549,15 +27681,15 @@ function codingRelativePath(value, field = "cwd") {
27549
27681
  }
27550
27682
  function validateCodingEnvironmentConfig(input) {
27551
27683
  const config2 = object(input, ["image", "cwd", "env"], "configuration");
27552
- const image = text(config2.image, 512, "image");
27553
- if (!/^[A-Za-z0-9][A-Za-z0-9._/:@-]*$/.test(image)) invalid2("image");
27684
+ const image2 = text(config2.image, 512, "image");
27685
+ if (!/^[A-Za-z0-9][A-Za-z0-9._/:@-]*$/.test(image2)) invalid2("image");
27554
27686
  const cwd = codingRelativePath(config2.cwd);
27555
27687
  const env = object(config2.env, ["CI", "NO_COLOR", "TZ"], "environment values");
27556
27688
  for (const [key3, value] of Object.entries(env)) {
27557
27689
  const allowed = key3 === "CI" ? ["true", "false"] : key3 === "NO_COLOR" ? ["0", "1"] : ["UTC"];
27558
27690
  if (typeof value !== "string" || !allowed.includes(value)) invalid2("environment values");
27559
27691
  }
27560
- return { image, cwd, env };
27692
+ return { image: image2, cwd, env };
27561
27693
  }
27562
27694
  function validateCodingCommand(input) {
27563
27695
  const value = object(input, ["command", "cwd", "purpose", "timeoutSeconds"], "command");
@@ -28180,13 +28312,13 @@ function validateDockerExecutableIdentity(identity2) {
28180
28312
  }
28181
28313
  }
28182
28314
  function createDockerBashOperations(options) {
28183
- const image = options.image;
28315
+ const image2 = options.image;
28184
28316
  const env = { ...options.env };
28185
28317
  const dockerPath = options.dockerPath ?? "docker";
28186
28318
  const configuredReadOnlyMounts = options.readOnlyMounts ?? [];
28187
28319
  const hostEnv = { ...options.hostEnv ?? process.env };
28188
28320
  validateDockerPath(dockerPath);
28189
- validateImage(image);
28321
+ validateImage(image2);
28190
28322
  return {
28191
28323
  async exec(command, cwd, { onData, signal, timeout }) {
28192
28324
  const timeoutMs = resolveTimeoutMs(timeout);
@@ -28206,11 +28338,11 @@ function createDockerBashOperations(options) {
28206
28338
  if (signal?.aborted) throw new Error("aborted");
28207
28339
  const { uid, gid } = hostIdentity();
28208
28340
  const dockerClientEnv = await resolveLocalDockerClientEnv(dockerPath, hostEnv);
28209
- const resolvedImage = await inspectSandboxImage(dockerPath, image, dockerClientEnv);
28341
+ const resolvedImage = await inspectSandboxImage(dockerPath, image2, dockerClientEnv);
28210
28342
  if (signal?.aborted) throw new Error("aborted");
28211
28343
  const containerName = options.lifecycle?.name("bash") ?? `bazilion-bash-${process.pid}-${randomUUID25().replaceAll("-", "")}`;
28212
28344
  const spec = buildDockerRunSpec({
28213
- image,
28345
+ image: image2,
28214
28346
  env,
28215
28347
  dockerPath,
28216
28348
  command,
@@ -28443,25 +28575,25 @@ async function inspectDockerEndpoint(dockerPath, processEnv) {
28443
28575
  );
28444
28576
  }
28445
28577
  }
28446
- async function inspectSandboxImage(dockerPath, image, processEnv) {
28578
+ async function inspectSandboxImage(dockerPath, image2, processEnv) {
28447
28579
  let raw2;
28448
28580
  try {
28449
28581
  raw2 = await runDockerInspection(
28450
28582
  dockerPath,
28451
- ["image", "inspect", "--format", '{{json .Id}} {{json (index .Config "Volumes")}}', image],
28583
+ ["image", "inspect", "--format", '{{json .Id}} {{json (index .Config "Volumes")}}', image2],
28452
28584
  processEnv,
28453
- `local image ${JSON.stringify(image)}`
28585
+ `local image ${JSON.stringify(image2)}`
28454
28586
  );
28455
28587
  } catch (error2) {
28456
28588
  const detail3 = error2 instanceof Error ? error2.message : String(error2);
28457
28589
  if (/no such image|unable to find image|manifest unknown/i.test(detail3)) {
28458
- throw new Error(`Docker sandbox image "${image}" is unavailable: ${detail3}`);
28590
+ throw new Error(`Docker sandbox image "${image2}" is unavailable: ${detail3}`);
28459
28591
  }
28460
28592
  throw error2;
28461
28593
  }
28462
28594
  const separator = raw2.indexOf(" ");
28463
28595
  if (separator < 0) {
28464
- throw new Error(`Docker sandbox received an invalid inspection result for image "${image}"`);
28596
+ throw new Error(`Docker sandbox received an invalid inspection result for image "${image2}"`);
28465
28597
  }
28466
28598
  let id;
28467
28599
  let volumes;
@@ -28469,18 +28601,18 @@ async function inspectSandboxImage(dockerPath, image, processEnv) {
28469
28601
  id = JSON.parse(raw2.slice(0, separator));
28470
28602
  volumes = JSON.parse(raw2.slice(separator + 1));
28471
28603
  } catch {
28472
- throw new Error(`Docker sandbox received an invalid inspection result for image "${image}"`);
28604
+ throw new Error(`Docker sandbox received an invalid inspection result for image "${image2}"`);
28473
28605
  }
28474
28606
  if (typeof id !== "string" || !id.startsWith("sha256:")) {
28475
- throw new Error(`Docker sandbox received an invalid image id for "${image}"`);
28607
+ throw new Error(`Docker sandbox received an invalid image id for "${image2}"`);
28476
28608
  }
28477
28609
  if (volumes !== null && typeof volumes === "object" && Object.keys(volumes).length > 0) {
28478
28610
  throw new Error(
28479
- `Docker sandbox image "${image}" declares writable volumes (${Object.keys(volumes).sort().join(", ")}); use an image without VOLUME declarations`
28611
+ `Docker sandbox image "${image2}" declares writable volumes (${Object.keys(volumes).sort().join(", ")}); use an image without VOLUME declarations`
28480
28612
  );
28481
28613
  }
28482
28614
  if (volumes !== null && (typeof volumes !== "object" || Array.isArray(volumes))) {
28483
- throw new Error(`Docker sandbox received invalid volume metadata for image "${image}"`);
28615
+ throw new Error(`Docker sandbox received invalid volume metadata for image "${image2}"`);
28484
28616
  }
28485
28617
  return id;
28486
28618
  }
@@ -28543,12 +28675,12 @@ function validateDockerPath(dockerPath) {
28543
28675
  if (dockerPath.includes("\0"))
28544
28676
  throw new Error("Docker sandbox executable path contains a NUL byte");
28545
28677
  }
28546
- function validateImage(image) {
28547
- if (!image.trim()) throw new Error("Docker sandbox image is required");
28548
- if (image.startsWith("-")) {
28549
- throw new Error(`Docker sandbox image cannot start with "-": ${JSON.stringify(image)}`);
28678
+ function validateImage(image2) {
28679
+ if (!image2.trim()) throw new Error("Docker sandbox image is required");
28680
+ if (image2.startsWith("-")) {
28681
+ throw new Error(`Docker sandbox image cannot start with "-": ${JSON.stringify(image2)}`);
28550
28682
  }
28551
- if (image.includes("\0")) throw new Error("Docker sandbox image contains a NUL byte");
28683
+ if (image2.includes("\0")) throw new Error("Docker sandbox image contains a NUL byte");
28552
28684
  }
28553
28685
  function validateContainerName(containerName) {
28554
28686
  if (!CONTAINER_NAME.test(containerName)) {
@@ -30124,6 +30256,7 @@ function piMessagesToProviderView(messages, questionResultVisible) {
30124
30256
  toolCallId: tr.toolCallId,
30125
30257
  toolName: tr.toolName,
30126
30258
  result: extractResultReference(m2),
30259
+ results: extractResultReferences(m2),
30127
30260
  ...images.length > 0 ? { images } : {}
30128
30261
  });
30129
30262
  break;
@@ -30134,6 +30267,15 @@ function piMessagesToProviderView(messages, questionResultVisible) {
30134
30267
  }
30135
30268
  return out;
30136
30269
  }
30270
+ function extractResultReferences(value) {
30271
+ if (!value || typeof value !== "object") return void 0;
30272
+ const refs = value.details?.results;
30273
+ if (!Array.isArray(refs) || refs.length > 4) return void 0;
30274
+ return refs.flatMap((ref) => {
30275
+ const parsed = extractResultReference({ details: { result: ref } });
30276
+ return parsed ? [parsed] : [];
30277
+ });
30278
+ }
30137
30279
  function extractResultReference(value) {
30138
30280
  if (!value || typeof value !== "object") return void 0;
30139
30281
  const details = value.details;
@@ -31051,6 +31193,8 @@ var PROTECTED_PROVIDER_NAMES = [
31051
31193
  "opencode",
31052
31194
  "opencode-go",
31053
31195
  "zai-coding-cn",
31196
+ "meta",
31197
+ "radius",
31054
31198
  "github-copilot",
31055
31199
  "cloudflare-ai-gateway",
31056
31200
  "cloudflare-workers-ai",
@@ -31101,6 +31245,8 @@ var PROVIDER_API_KEY_ENV = {
31101
31245
  opencode: ["OPENCODE_API_KEY"],
31102
31246
  "opencode-go": ["OPENCODE_GO_API_KEY"],
31103
31247
  "zai-coding-cn": ["ZAI_CODING_CN_API_KEY"],
31248
+ meta: ["META_API_KEY"],
31249
+ radius: ["RADIUS_API_KEY"],
31104
31250
  "github-copilot": ["COPILOT_GITHUB_TOKEN"],
31105
31251
  "cloudflare-ai-gateway": ["CLOUDFLARE_API_KEY"],
31106
31252
  "cloudflare-workers-ai": ["CLOUDFLARE_API_KEY"],
@@ -31644,6 +31790,8 @@ function loadProviderConfigFromEnv(env = process.env, oauth) {
31644
31790
  if (env.OPENCODE_API_KEY) config2.opencode = { apiKey: env.OPENCODE_API_KEY };
31645
31791
  if (env.OPENCODE_GO_API_KEY) config2.opencodeGo = { apiKey: env.OPENCODE_GO_API_KEY };
31646
31792
  if (env.ZAI_CODING_CN_API_KEY) config2.zaiCodingCn = { apiKey: env.ZAI_CODING_CN_API_KEY };
31793
+ if (env.META_API_KEY) config2.meta = { apiKey: env.META_API_KEY };
31794
+ if (env.RADIUS_API_KEY) config2.radius = { apiKey: env.RADIUS_API_KEY };
31647
31795
  if (env.COPILOT_GITHUB_TOKEN) config2.githubCopilot = { apiKey: env.COPILOT_GITHUB_TOKEN };
31648
31796
  if (env.CLOUDFLARE_API_KEY && env.CLOUDFLARE_ACCOUNT_ID) {
31649
31797
  config2.cloudflareWorkersAi = {
@@ -31991,6 +32139,24 @@ var PROVIDERS = {
31991
32139
  }),
31992
32140
  hint: "ZAI_CODING_CN_API_KEY"
31993
32141
  },
32142
+ meta: {
32143
+ configured: (c) => !!c.meta,
32144
+ build: (c) => piProvider({
32145
+ providerName: "meta",
32146
+ apiKey: c.meta?.apiKey,
32147
+ baseUrl: c.meta?.baseURL
32148
+ }),
32149
+ hint: "META_API_KEY"
32150
+ },
32151
+ radius: {
32152
+ configured: (c) => !!c.radius,
32153
+ build: (c) => piProvider({
32154
+ providerName: "radius",
32155
+ apiKey: c.radius?.apiKey,
32156
+ baseUrl: c.radius?.baseURL
32157
+ }),
32158
+ hint: "RADIUS_API_KEY"
32159
+ },
31994
32160
  "github-copilot": {
31995
32161
  configured: (c) => !!c.githubCopilot,
31996
32162
  build: (c) => piProvider({
@@ -32458,6 +32624,8 @@ var REASONING_LEVELS2 = /* @__PURE__ */ new Set([
32458
32624
  var CONFIGURED_KEYS = /* @__PURE__ */ new Set([
32459
32625
  "containerNamespace",
32460
32626
  "configuredDocker",
32627
+ "imageGenerationEnabled",
32628
+ "webSearchEnabled",
32461
32629
  "repositoryContext",
32462
32630
  "questionEnabled",
32463
32631
  "conversation",
@@ -32485,6 +32653,7 @@ var CONFIGURED_REQUIRED_KEYS = /* @__PURE__ */ new Set([
32485
32653
  "bashApprovalMode"
32486
32654
  ]);
32487
32655
  var PROTECTED_KEYS = /* @__PURE__ */ new Set([
32656
+ "imageGenerationEnabled",
32488
32657
  "containerNamespace",
32489
32658
  "repositoryContext",
32490
32659
  "questionEnabled",
@@ -32499,12 +32668,13 @@ var PROTECTED_KEYS = /* @__PURE__ */ new Set([
32499
32668
  "paths",
32500
32669
  "docker",
32501
32670
  "webFetchEnabled",
32671
+ "webSearchEnabled",
32502
32672
  "apiKeyRefreshEnabled",
32503
32673
  "scratch"
32504
32674
  ]);
32505
32675
  var PROTECTED_REQUIRED_KEYS = new Set(
32506
32676
  [...PROTECTED_KEYS].filter(
32507
- (key3) => key3 !== "images" && key3 !== "questionEnabled" && key3 !== "containerNamespace"
32677
+ (key3) => key3 !== "images" && key3 !== "questionEnabled" && key3 !== "containerNamespace" && key3 !== "imageGenerationEnabled" && key3 !== "webSearchEnabled"
32508
32678
  )
32509
32679
  );
32510
32680
  var STATIC_REVIEW_KEYS = /* @__PURE__ */ new Set([
@@ -32599,6 +32769,10 @@ function parseWorkerInput(value) {
32599
32769
  const kind = input.kind;
32600
32770
  if (input.containerNamespace !== void 0 && (typeof input.containerNamespace !== "string" || !/^[a-f0-9-]{36}$/.test(input.containerNamespace)))
32601
32771
  throw new Error("Invalid container namespace");
32772
+ if (input.imageGenerationEnabled !== void 0 && typeof input.imageGenerationEnabled !== "boolean")
32773
+ throw new Error("Invalid worker image capability");
32774
+ if (input.webSearchEnabled !== void 0 && typeof input.webSearchEnabled !== "boolean")
32775
+ throw new Error("Invalid worker web search capability");
32602
32776
  if (input.questionEnabled !== void 0 && typeof input.questionEnabled !== "boolean")
32603
32777
  throw new Error("Invalid worker question capability");
32604
32778
  if (kind === "configured_operator_http") {
@@ -33716,6 +33890,53 @@ function rejectExistingSymlinkOrNonFile(path) {
33716
33890
  }
33717
33891
  }
33718
33892
 
33893
+ // ../daemon/src/runtime/tools/image-generate.ts
33894
+ function imageGenerateTool(generate, sessionId) {
33895
+ return {
33896
+ def: {
33897
+ name: "image_generate",
33898
+ description: "Generate original images from a text prompt using the operator-selected image route/model (API billing or ChatGPT subscription usage). Saved Results are delivered subject to Team Policy. Rework is a new generation, not a pixel edit. Do not automatically retry a failed or uncertain request; it may already have been billed. No social publication.",
33899
+ parameters: {
33900
+ type: "object",
33901
+ properties: {
33902
+ prompt: {
33903
+ type: "string",
33904
+ description: "Describe the desired image. Maximum 8 KiB UTF-8."
33905
+ },
33906
+ name: {
33907
+ type: "string",
33908
+ description: "Optional display filename, not a path (ASCII, maximum 120 characters)."
33909
+ }
33910
+ },
33911
+ required: ["prompt"],
33912
+ additionalProperties: false
33913
+ }
33914
+ },
33915
+ async invoke(args, context) {
33916
+ if (!context?.toolCallId || !sessionId)
33917
+ throw new Error("image_generate: missing source operation");
33918
+ if (typeof args.prompt !== "string" || args.name !== void 0 && typeof args.name !== "string" || Object.keys(args).some((key3) => !["prompt", "name"].includes(key3))) {
33919
+ throw new Error("image_generate: invalid arguments");
33920
+ }
33921
+ const output = await generate({
33922
+ sessionId,
33923
+ toolCallId: context.toolCallId,
33924
+ prompt: args.prompt,
33925
+ ...args.name === void 0 ? {} : { name: args.name }
33926
+ });
33927
+ return {
33928
+ content: [
33929
+ {
33930
+ type: "text",
33931
+ text: `Saved ${output.files.length} image(s) via ${imageGenerationRouteLabel(output.model)} (selected: ${output.model}). Delivery is subject to Team Policy. ${output.files.map((file) => `${file.name}: ${file.result.resultId}`).join("; ")}`
33932
+ }
33933
+ ],
33934
+ results: output.files.map((file) => file.result)
33935
+ };
33936
+ }
33937
+ };
33938
+ }
33939
+
33719
33940
  // ../daemon/src/runtime/tools/mcp.ts
33720
33941
  function mcpProxyTools(host2, tools) {
33721
33942
  return tools.map((t) => ({
@@ -34806,7 +35027,7 @@ function ourToolToPiTool(h) {
34806
35027
  const out = await h.invoke(params, { toolCallId });
34807
35028
  return {
34808
35029
  content: toPiContent(out),
34809
- details: typeof out === "object" && !Array.isArray(out) ? "result" in out ? { result: out.result } : { questionReceipt: out.questionReceipt } : {}
35030
+ details: typeof out === "object" && !Array.isArray(out) ? "result" in out ? { result: out.result } : "results" in out ? { results: out.results } : { questionReceipt: out.questionReceipt } : {}
34810
35031
  };
34811
35032
  }
34812
35033
  };
@@ -34839,6 +35060,14 @@ function createBazilionCustomTools(opts) {
34839
35060
  if (opts.fileSink) {
34840
35061
  handlers.push(deliverFileTool(opts.agent.team.path, opts.fileSink, opts.sessionId));
34841
35062
  }
35063
+ if (opts.imageGenerationHost) {
35064
+ handlers.push(
35065
+ imageGenerateTool(
35066
+ opts.imageGenerationHost.generate.bind(opts.imageGenerationHost),
35067
+ opts.sessionId ?? ""
35068
+ )
35069
+ );
35070
+ }
34842
35071
  if (opts.verificationRequestHost) {
34843
35072
  handlers.push(verificationRequestTool(opts.verificationRequestHost));
34844
35073
  }
@@ -34940,6 +35169,7 @@ async function createBazilionSession(opts) {
34940
35169
  mcpHost,
34941
35170
  mcpTools,
34942
35171
  fileSink,
35172
+ imageGenerationHost: opts.imageGenerationHost,
34943
35173
  askUser,
34944
35174
  sessionId: sessionManager.getSessionId(),
34945
35175
  env,
@@ -35552,6 +35782,9 @@ function isRestrictedWorkerKind(spec) {
35552
35782
  }
35553
35783
  function assertSpawnCombination(spec, opts) {
35554
35784
  const record3 = opts;
35785
+ if (!isRestrictedWorkerKind(spec) && (Boolean(spec.imageGenerationEnabled) !== Boolean(record3.imageGenerationHost) || record3.imageGenerationHost && !hostHasMethods(record3.imageGenerationHost, ["generate"]))) {
35786
+ throw new Error("Image generation capability requires its bound host");
35787
+ }
35555
35788
  if (!isRestrictedWorkerKind(spec) && (Boolean(spec.questionEnabled) !== Boolean(record3.questionHost) || record3.questionHost && !hostHasMethods(record3.questionHost, ["ask", "close", "subscribe", "consumed"])))
35556
35789
  throw new Error("Question capability requires its bound host");
35557
35790
  if (spec.kind === "configured_operator_http") {
@@ -35591,6 +35824,7 @@ function assertSpawnCombination(spec, opts) {
35591
35824
  "containerHost",
35592
35825
  "repositoryContextHost",
35593
35826
  "resultHost",
35827
+ "imageGenerationHost",
35594
35828
  "resourceLifecycle",
35595
35829
  // Not just "a restricted turn has no reason to ask": the requester capability captures a
35596
35830
  // snapshot and writes a request, so handing it to any restricted kind would give that turn a
@@ -35645,6 +35879,8 @@ function spawnHosts(spec, opts, signal, onBashApproval, onQuestion, onApiKeyRefr
35645
35879
  codingHost: restricted ? void 0 : opts.codingHost,
35646
35880
  repositoryContextHost: restricted ? void 0 : opts.repositoryContextHost,
35647
35881
  resultHost: restricted ? void 0 : opts.resultHost,
35882
+ imageGenerationHost: restricted ? void 0 : opts.imageGenerationHost,
35883
+ webSearchHost: restricted ? void 0 : opts.webSearchHost,
35648
35884
  // A verification turn reads its request and runs captured checks; it does not message peers,
35649
35885
  // edit USER.md, drive a browser or call MCP. Cleared here rather than trusting the caller.
35650
35886
  messagingHost: restricted ? void 0 : configuredOpts?.messagingHost ?? protectedOpts?.messagingHost,
@@ -35749,6 +35985,20 @@ async function dispatch(req, hosts) {
35749
35985
  );
35750
35986
  break;
35751
35987
  }
35988
+ case "generateImages":
35989
+ hosts.ipcSignal?.throwIfAborted();
35990
+ result = await require2(hosts.imageGenerationHost, "image generation", req.method).generate(
35991
+ req.args
35992
+ );
35993
+ break;
35994
+ case "webSearch": {
35995
+ hosts.ipcSignal?.throwIfAborted();
35996
+ const args = req.args;
35997
+ if (!args || typeof args.query !== "string" || args.query.length > 512 || args.count !== void 0 && (!Number.isInteger(args.count) || args.count < 1 || args.count > 8))
35998
+ throw new Error("Invalid web search IPC request");
35999
+ result = await require2(hosts.webSearchHost, "web search", req.method).search(args);
36000
+ break;
36001
+ }
35752
36002
  case "publishResult":
35753
36003
  hosts.ipcSignal?.throwIfAborted();
35754
36004
  result = await require2(hosts.resultHost, "result", req.method).publish(req.args);
@@ -37020,7 +37270,8 @@ var MAX_RETAINED_RESULT_BYTES = 1024 * 1024 * 1024;
37020
37270
  var columns2 = `id, team_id AS teamId, agent_id AS agentId, source_kind AS sourceKind,
37021
37271
  session_id AS sessionId, tool_call_id AS toolCallId, review_packet_id AS reviewPacketId,
37022
37272
  review_revision AS reviewRevision, name, mime_type AS mimeType, byte_length AS byteLength,
37023
- sha256, created_at AS createdAt, released_at AS releasedAt, deleted_at AS deletedAt`;
37273
+ sha256, created_at AS createdAt, released_at AS releasedAt, deleted_at AS deletedAt,
37274
+ source_index AS sourceIndex, image_model AS imageModel`;
37024
37275
  function validIdentity(value) {
37025
37276
  return typeof value === "string" && /^[A-Za-z0-9._:-]{1,256}$/.test(value);
37026
37277
  }
@@ -37048,20 +37299,24 @@ function publish(db, input) {
37048
37299
  if (!(input.bytes instanceof Uint8Array) || input.bytes.byteLength > MAX_RESULT_BYTES) {
37049
37300
  throw new Error("Result exceeds the 25 MiB per-file limit");
37050
37301
  }
37302
+ const sourceIndex = input.sourceIndex ?? 0;
37303
+ if (!Number.isInteger(sourceIndex) || sourceIndex < 0 || sourceIndex > 3) {
37304
+ throw new Error("Invalid result source index");
37305
+ }
37051
37306
  const bytes = Buffer.from(input.bytes);
37052
37307
  const sha256 = createHash10("sha256").update(bytes).digest("hex");
37053
37308
  return db.raw.transaction(() => {
37054
37309
  const existing = source === "session_tool" ? db.raw.query(
37055
37310
  `SELECT ${columns2} FROM agent_results
37056
- WHERE agent_id = ? AND source_kind = 'session_tool' AND session_id = ? AND tool_call_id = ?`
37057
- ).get(input.agentId, input.sessionId, input.toolCallId) : db.raw.query(
37311
+ WHERE agent_id = ? AND source_kind = 'session_tool' AND session_id = ? AND tool_call_id = ? AND source_index = ?`
37312
+ ).get(input.agentId, input.sessionId, input.toolCallId, sourceIndex) : db.raw.query(
37058
37313
  `SELECT ${columns2} FROM agent_results
37059
37314
  WHERE agent_id = ? AND source_kind = 'review_packet' AND review_packet_id = ?
37060
37315
  AND review_revision = ?`
37061
37316
  ).get(input.agentId, input.reviewPacketId, input.reviewRevision);
37062
37317
  if (existing) {
37063
37318
  if (existing.deletedAt !== null) throw new Error("Captured result was deleted");
37064
- if (existing.teamId !== input.teamId || existing.sha256 !== sha256 || existing.name !== input.name || existing.mimeType !== input.mimeType) {
37319
+ if (existing.teamId !== input.teamId || existing.sha256 !== sha256 || existing.name !== input.name || existing.mimeType !== input.mimeType || existing.imageModel !== (input.imageModel ?? null)) {
37065
37320
  throw new Error("Result publication retry does not match the captured operation");
37066
37321
  }
37067
37322
  return existing;
@@ -37081,8 +37336,8 @@ function publish(db, input) {
37081
37336
  db.raw.run(
37082
37337
  `INSERT INTO agent_results
37083
37338
  (id, team_id, agent_id, source_kind, session_id, tool_call_id, review_packet_id, review_revision,
37084
- name, mime_type, byte_length, sha256, created_at, bytes)
37085
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
37339
+ name, mime_type, byte_length, sha256, created_at, bytes, source_index, image_model)
37340
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
37086
37341
  [
37087
37342
  id,
37088
37343
  input.teamId,
@@ -37097,7 +37352,9 @@ function publish(db, input) {
37097
37352
  bytes.byteLength,
37098
37353
  sha256,
37099
37354
  Date.now(),
37100
- bytes
37355
+ bytes,
37356
+ sourceIndex,
37357
+ input.imageModel ?? null
37101
37358
  ]
37102
37359
  );
37103
37360
  const result = getReceipt(db, id);
@@ -39281,6 +39538,467 @@ function createCodingHost(input) {
39281
39538
  };
39282
39539
  }
39283
39540
 
39541
+ // ../daemon/src/lib/image-generation.ts
39542
+ import { createHash as createHash12 } from "crypto";
39543
+ import { createImagesModels } from "@earendil-works/pi-ai";
39544
+ import { openrouterImagesProvider } from "@earendil-works/pi-ai/providers/openrouter-images";
39545
+
39546
+ // ../daemon/src/core/repos/image-generations.ts
39547
+ function admit2(db, op) {
39548
+ return db.raw.transaction(() => {
39549
+ const previous = db.raw.query(`SELECT team_id, request_sha256, model, outcome FROM image_generations
39550
+ WHERE agent_id = ? AND session_id = ? AND tool_call_id = ?`).get(op.agentId, op.sessionId, op.toolCallId);
39551
+ if (previous) {
39552
+ if (previous.team_id !== op.teamId || previous.request_sha256 !== op.requestSha256 || previous.model !== op.model) {
39553
+ throw new Error("Image operation retry does not match its captured request");
39554
+ }
39555
+ if (previous.outcome === "completed") return "completed";
39556
+ throw new Error(
39557
+ `Image operation is ${previous.outcome}; it will not be automatically regenerated. It may have been billed.`
39558
+ );
39559
+ }
39560
+ const uncertain = db.raw.query(
39561
+ "SELECT count(*) AS n FROM image_generations WHERE turn_id = ? AND outcome = 'uncertain'"
39562
+ ).get(op.turnId)?.n ?? 0;
39563
+ if (uncertain > 0)
39564
+ throw new Error(
39565
+ "A previous image request is uncertain. Generation is blocked for the rest of this turn; inspect Results before starting a new turn."
39566
+ );
39567
+ const count3 = db.raw.query(
39568
+ "SELECT count(*) AS n FROM image_generations WHERE turn_id = ?"
39569
+ ).get(op.turnId)?.n ?? 0;
39570
+ if (count3 >= 4) throw new Error("Image generation limit reached (four requests per turn)");
39571
+ db.raw.run(
39572
+ `INSERT INTO image_generations
39573
+ (agent_id, team_id, session_id, tool_call_id, turn_id, request_sha256, model, outcome, created_at)
39574
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'uncertain', ?)`,
39575
+ [
39576
+ op.agentId,
39577
+ op.teamId,
39578
+ op.sessionId,
39579
+ op.toolCallId,
39580
+ op.turnId,
39581
+ op.requestSha256,
39582
+ op.model,
39583
+ Date.now()
39584
+ ]
39585
+ );
39586
+ return "new";
39587
+ })();
39588
+ }
39589
+ function settle2(db, op, outcome, responseId2 = null, usage2 = null) {
39590
+ const { changes } = db.raw.run(
39591
+ `UPDATE image_generations
39592
+ SET outcome = ?, response_id = ?, usage_json = ?
39593
+ WHERE agent_id = ? AND session_id = ? AND tool_call_id = ? AND outcome = 'uncertain'`,
39594
+ [outcome, responseId2, usage2, op.agentId, op.sessionId, op.toolCallId]
39595
+ );
39596
+ if (changes !== 1) throw new Error("Image operation is no longer available");
39597
+ }
39598
+ function resultIds(db, op) {
39599
+ return db.raw.query(`SELECT id FROM agent_results
39600
+ WHERE agent_id = ? AND team_id = ? AND session_id = ? AND tool_call_id = ?
39601
+ AND source_kind = 'session_tool' ORDER BY source_index`).all(op.agentId, op.teamId, op.sessionId, op.toolCallId).map((row2) => row2.id);
39602
+ }
39603
+
39604
+ // ../daemon/src/lib/image-transport.ts
39605
+ var IMAGE_RESPONSE_BYTES = 40 * 1024 * 1024;
39606
+ var endpoints = {
39607
+ openrouter: "https://openrouter.ai/api/v1/chat/completions",
39608
+ openai: "https://api.openai.com/v1/images/generations",
39609
+ "openai-codex": "https://chatgpt.com/backend-api/codex/responses"
39610
+ };
39611
+ function boundedImageFetch(fetcher = fetch, provider = "openrouter") {
39612
+ return async (input, init) => {
39613
+ const url2 = new URL(input instanceof Request ? input.url : String(input));
39614
+ if (url2.href !== endpoints[provider]) throw new Error("Unexpected image provider endpoint");
39615
+ const response = await fetcher(input, { ...init, redirect: "error" });
39616
+ const reader = response.body?.getReader();
39617
+ if (!reader) throw new Error("Image provider returned no response body");
39618
+ const chunks = [];
39619
+ let size = 0;
39620
+ try {
39621
+ if (Number(response.headers.get("content-length")) > IMAGE_RESPONSE_BYTES)
39622
+ throw new Error("Image response exceeds the byte limit");
39623
+ while (true) {
39624
+ const { done, value } = await reader.read();
39625
+ if (done) break;
39626
+ size += value.byteLength;
39627
+ if (size > IMAGE_RESPONSE_BYTES) throw new Error("Image response exceeds the byte limit");
39628
+ chunks.push(value);
39629
+ }
39630
+ } finally {
39631
+ await reader.cancel().catch(() => {
39632
+ });
39633
+ reader.releaseLock();
39634
+ }
39635
+ return new Response(Buffer.concat(chunks), {
39636
+ status: response.status,
39637
+ statusText: response.statusText,
39638
+ headers: response.headers
39639
+ });
39640
+ };
39641
+ }
39642
+ async function imageAbortable(promise, signal) {
39643
+ let abort = () => {
39644
+ };
39645
+ const cancelled = new Promise((_2, reject2) => {
39646
+ abort = () => reject2(new Error("Image request aborted"));
39647
+ if (signal.aborted) abort();
39648
+ else signal.addEventListener("abort", abort, { once: true });
39649
+ });
39650
+ try {
39651
+ return await Promise.race([promise, cancelled]);
39652
+ } finally {
39653
+ signal.removeEventListener("abort", abort);
39654
+ }
39655
+ }
39656
+ function object3(value) {
39657
+ if (!value || typeof value !== "object" || Array.isArray(value))
39658
+ throw new Error("Malformed image response");
39659
+ return value;
39660
+ }
39661
+ function usage(value) {
39662
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
39663
+ const raw2 = value;
39664
+ const number4 = (key3) => typeof raw2[key3] === "number" && Number.isFinite(raw2[key3]) && raw2[key3] >= 0 ? raw2[key3] : void 0;
39665
+ return {
39666
+ input: number4("input_tokens"),
39667
+ output: number4("output_tokens"),
39668
+ totalTokens: number4("total_tokens")
39669
+ };
39670
+ }
39671
+ function responseId(value) {
39672
+ return typeof value === "string" ? value : void 0;
39673
+ }
39674
+ function image(data) {
39675
+ if (typeof data !== "string" || !data) throw new Error("Missing image bytes");
39676
+ return { type: "image", mimeType: "image/png", data };
39677
+ }
39678
+ async function generateOpenAIImages(opts) {
39679
+ const codex = opts.provider === "openai-codex";
39680
+ opts.signal.throwIfAborted();
39681
+ const response = await boundedImageFetch(opts.fetch, opts.provider)(endpoints[opts.provider], {
39682
+ method: "POST",
39683
+ signal: opts.signal,
39684
+ headers: {
39685
+ Authorization: `Bearer ${opts.apiKey}`,
39686
+ "Content-Type": "application/json",
39687
+ Accept: codex ? "text/event-stream" : "application/json"
39688
+ },
39689
+ body: JSON.stringify(
39690
+ codex ? {
39691
+ model: "gpt-6-astra",
39692
+ instructions: "Generate the requested image using the image generation tool.",
39693
+ input: [{ role: "user", content: [{ type: "input_text", text: opts.prompt }] }],
39694
+ tools: [
39695
+ {
39696
+ type: "image_generation",
39697
+ model: "gpt-image-2",
39698
+ size: "1024x1024",
39699
+ output_format: "png"
39700
+ }
39701
+ ],
39702
+ tool_choice: { type: "image_generation" },
39703
+ stream: true,
39704
+ store: false
39705
+ } : {
39706
+ model: "gpt-image-2",
39707
+ prompt: opts.prompt,
39708
+ n: 1,
39709
+ size: "1024x1024",
39710
+ output_format: "png"
39711
+ }
39712
+ )
39713
+ });
39714
+ if (!response.ok) throw new Error("Image provider rejected the request");
39715
+ if (codex) {
39716
+ if (!response.headers.get("content-type")?.toLowerCase().startsWith("text/event-stream"))
39717
+ throw new Error("Expected image event stream");
39718
+ return readCodexImages(await response.text());
39719
+ }
39720
+ const body = object3(await response.json());
39721
+ if (!Array.isArray(body.data) || body.data.length < 1 || body.data.length > 4)
39722
+ throw new Error("Missing or excessive image output");
39723
+ return {
39724
+ stopReason: "stop",
39725
+ output: body.data.map((entry) => image(object3(entry).b64_json)),
39726
+ responseId: responseId(body.id),
39727
+ usage: usage(body.usage)
39728
+ };
39729
+ }
39730
+ function checkImageId(id, seen) {
39731
+ if (id == null) return;
39732
+ if (typeof id !== "string" || !id || id.length > 256 || seen.has(id))
39733
+ throw new Error("Invalid or duplicate image identity");
39734
+ seen.add(id);
39735
+ }
39736
+ function readCodexImages(body) {
39737
+ let completed;
39738
+ const done = [];
39739
+ const doneIds = /* @__PURE__ */ new Set();
39740
+ let count3 = 0;
39741
+ for (const frame of body.replace(/\r\n?/g, "\n").split("\n\n")) {
39742
+ const data = frame.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n").trim();
39743
+ if (!data || data === "[DONE]") continue;
39744
+ if (++count3 > 512) throw new Error("Too many image stream events");
39745
+ const event2 = object3(JSON.parse(data));
39746
+ if (["error", "response.failed", "response.incomplete"].includes(String(event2.type)))
39747
+ throw new Error("Image stream failed or was incomplete");
39748
+ if (event2.type === "response.completed") {
39749
+ if (completed) throw new Error("Duplicate image completion");
39750
+ completed = object3(event2.response);
39751
+ if (completed.error != null || completed.status != null && completed.status !== "completed")
39752
+ throw new Error("Image response was not completed");
39753
+ }
39754
+ if (event2.type === "response.output_item.done") {
39755
+ const item = object3(event2.item);
39756
+ if (item.type !== "image_generation_call") continue;
39757
+ checkImageId(item.id, doneIds);
39758
+ done.push(item);
39759
+ if (done.length > 4) throw new Error("Too many images");
39760
+ }
39761
+ }
39762
+ if (!completed) throw new Error("Image stream closed before completion");
39763
+ const output = completed.output === void 0 ? done : completed.output;
39764
+ if (!Array.isArray(output)) throw new Error("Malformed image output");
39765
+ const items = output.map(object3).filter((item) => item.type === "image_generation_call");
39766
+ if (items.length < 1 || items.length > 4) throw new Error("Missing or excessive image output");
39767
+ const ids = /* @__PURE__ */ new Set();
39768
+ const images = items.map((item) => {
39769
+ checkImageId(item.id, ids);
39770
+ if (item.status != null && item.status !== "completed")
39771
+ throw new Error("Image call did not complete");
39772
+ return image(item.result);
39773
+ });
39774
+ return {
39775
+ stopReason: "stop",
39776
+ output: images,
39777
+ responseId: responseId(completed.id),
39778
+ usage: usage(completed.usage)
39779
+ };
39780
+ }
39781
+
39782
+ // ../daemon/src/lib/image-generation.ts
39783
+ var IMAGE_DEADLINE_MS = 18e4;
39784
+ var busyHomes = /* @__PURE__ */ new WeakSet();
39785
+ var ImageGenerationError = class extends Error {
39786
+ };
39787
+ function imageCatalogue() {
39788
+ const models = createImagesModels({
39789
+ authContext: { env: async () => void 0, fileExists: async () => false }
39790
+ });
39791
+ models.setProvider(openrouterImagesProvider());
39792
+ return models;
39793
+ }
39794
+ function validateInput2(input) {
39795
+ if (!input || Object.keys(input).some(
39796
+ (key3) => !["sessionId", "toolCallId", "prompt", "name"].includes(key3)
39797
+ ) || typeof input.sessionId !== "string" || typeof input.toolCallId !== "string" || typeof input.prompt !== "string" || !input.prompt.trim() || Buffer.byteLength(input.prompt) > 8192) {
39798
+ throw new Error("image_generate requires a text prompt of at most 8 KiB and a valid source");
39799
+ }
39800
+ if (input.name !== void 0 && (typeof input.name !== "string" || !/^[A-Za-z0-9][A-Za-z0-9 _.-]{0,119}$/.test(input.name) || /[ .]$/.test(input.name) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:[ .]|$)/i.test(input.name))) {
39801
+ throw new Error("Image name must be a safe display filename (maximum 120 characters)");
39802
+ }
39803
+ }
39804
+ function decodeImages(response, name) {
39805
+ const images = response.output.filter((part) => part.type === "image");
39806
+ if (images.length === 0 || images.length > 4) {
39807
+ throw new ImageGenerationError(
39808
+ "Image provider returned no images or exceeded the four-image limit"
39809
+ );
39810
+ }
39811
+ return images.map((image2, index) => {
39812
+ if (image2.data.length > Math.ceil(MAX_RESULT_BYTES / 3) * 4 || image2.data.length % 4 !== 0) {
39813
+ throw new Error("Invalid or oversized image bytes");
39814
+ }
39815
+ const bytes = Buffer.from(image2.data, "base64");
39816
+ if (!bytes.length || bytes.length > MAX_RESULT_BYTES || bytes.toString("base64") !== image2.data) {
39817
+ throw new Error("Invalid or oversized image bytes");
39818
+ }
39819
+ const extension = image2.mimeType === "image/png" && bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) ? "png" : image2.mimeType === "image/jpeg" && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255 ? "jpg" : image2.mimeType === "image/webp" && bytes.subarray(0, 4).toString("ascii") === "RIFF" && bytes.subarray(8, 12).toString("ascii") === "WEBP" ? "webp" : null;
39820
+ if (!extension)
39821
+ throw new ImageGenerationError(
39822
+ "Image content does not match a supported PNG, JPEG or WebP type"
39823
+ );
39824
+ const stem = name.replace(/\.(png|jpe?g|webp)$/i, "");
39825
+ return {
39826
+ bytes,
39827
+ mimeType: image2.mimeType,
39828
+ name: `${stem}${images.length > 1 ? `-${index + 1}` : ""}.${extension}`
39829
+ };
39830
+ });
39831
+ }
39832
+ function safeUsage(usage2) {
39833
+ if (!usage2) return null;
39834
+ const counts = Object.fromEntries(
39835
+ ["input", "output", "cacheRead", "cacheWrite", "totalTokens"].map((key3) => {
39836
+ const value = usage2[key3];
39837
+ return [key3, typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null];
39838
+ })
39839
+ );
39840
+ const estimate = usage2.cost?.total;
39841
+ return JSON.stringify({
39842
+ ...counts,
39843
+ estimatedCost: typeof estimate === "number" && Number.isFinite(estimate) && estimate >= 0 ? estimate : null
39844
+ });
39845
+ }
39846
+ function createImageGenerationHost(opts) {
39847
+ const { db } = opts;
39848
+ const models = opts.models ?? imageCatalogue();
39849
+ const resolveConfig = () => imageGenerationConfig(opts.env(), opts.codex?.connected(), {
39850
+ enabledProviders: listEnabled(db),
39851
+ chatModel: opts.chatModel
39852
+ });
39853
+ const assertActive = () => {
39854
+ opts.signal.throwIfAborted();
39855
+ opts.assertActive();
39856
+ const owner = db.raw.query(
39857
+ "SELECT team_id, status FROM agents WHERE id = ?"
39858
+ ).get(opts.agentId);
39859
+ if (owner?.team_id !== opts.teamId || owner.status === "archived") {
39860
+ throw new Error("Image generation Agent is no longer active in this Team");
39861
+ }
39862
+ };
39863
+ const capturedOutput = (op) => {
39864
+ const ids = resultIds(db, op);
39865
+ if (!ids.length)
39866
+ throw new Error(
39867
+ "Generated results are unavailable; they will not be regenerated automatically"
39868
+ );
39869
+ return {
39870
+ model: op.model,
39871
+ files: ids.map((id) => {
39872
+ const receipt = getReceipt(db, id);
39873
+ if (!receipt || receipt.deletedAt !== null)
39874
+ throw new Error("Generated result was deleted; it will not be regenerated");
39875
+ return {
39876
+ name: receipt.name,
39877
+ mimeType: receipt.mimeType,
39878
+ data: readCaptured(db, id).toString("base64"),
39879
+ result: { resultId: id }
39880
+ };
39881
+ })
39882
+ };
39883
+ };
39884
+ return {
39885
+ async generate(input) {
39886
+ validateInput2(input);
39887
+ assertActive();
39888
+ const source = opts.source(input.sessionId, input.toolCallId);
39889
+ if (source.prompt !== input.prompt || source.name !== input.name || Object.keys(source).some((key3) => !["prompt", "name"].includes(key3))) {
39890
+ throw new Error("Image request does not match the canonical tool call");
39891
+ }
39892
+ const config2 = resolveConfig();
39893
+ if (!config2.ready) throw new Error(config2.status);
39894
+ const model = config2.provider === "openrouter" ? models.getModel("openrouter", config2.model) : void 0;
39895
+ if (config2.provider === "openrouter" && (model?.provider !== "openrouter" || model.api !== "openrouter-images" || model.baseUrl !== "https://openrouter.ai/api/v1" || !model.output.includes("image"))) {
39896
+ throw new Error("Selected Pi image model is unavailable; no fallback was attempted");
39897
+ }
39898
+ if (busyHomes.has(db))
39899
+ throw new Error("Image generation is busy; only one request per home may be in flight");
39900
+ const op = {
39901
+ agentId: opts.agentId,
39902
+ teamId: opts.teamId,
39903
+ turnId: opts.turnId,
39904
+ sessionId: input.sessionId,
39905
+ toolCallId: input.toolCallId,
39906
+ model: config2.model,
39907
+ requestSha256: createHash12("sha256").update(JSON.stringify([input.prompt, input.name ?? null])).digest("hex")
39908
+ };
39909
+ if (admit2(db, op) === "completed") return capturedOutput(op);
39910
+ busyHomes.add(db);
39911
+ const deadline = new AbortController();
39912
+ const timer = setTimeout(() => deadline.abort(), opts.deadlineMs ?? IMAGE_DEADLINE_MS);
39913
+ const signal = AbortSignal.any([opts.signal, deadline.signal]);
39914
+ try {
39915
+ let apiKey = config2.apiKey;
39916
+ if (config2.provider === "openai-codex") {
39917
+ try {
39918
+ if (!opts.codex) throw new Error("Missing login");
39919
+ apiKey = await imageAbortable(opts.codex.accessToken(), signal);
39920
+ } catch {
39921
+ throw new ImageGenerationError(
39922
+ "ChatGPT credentials unavailable. Reconnect ChatGPT on /config or run bazilion auth openai login. No API-key fallback or automatic retry."
39923
+ );
39924
+ }
39925
+ }
39926
+ signal.throwIfAborted();
39927
+ assertActive();
39928
+ const current = resolveConfig();
39929
+ if (!current.ready || current.model !== config2.model) {
39930
+ throw new ImageGenerationError(
39931
+ "Image configuration changed before dispatch. No image request was sent; inspect settings before starting a new turn. No billing-route fallback."
39932
+ );
39933
+ }
39934
+ if (!apiKey) throw new Error("Missing image credential");
39935
+ let pending;
39936
+ if (config2.provider === "openrouter") {
39937
+ if (!model) throw new Error("Selected Pi image model unavailable");
39938
+ pending = models.generateImages(
39939
+ model,
39940
+ { input: [{ type: "text", text: input.prompt }] },
39941
+ {
39942
+ apiKey,
39943
+ signal,
39944
+ timeoutMs: opts.deadlineMs ?? IMAGE_DEADLINE_MS,
39945
+ maxRetries: 0,
39946
+ fetch: boundedImageFetch(opts.fetch)
39947
+ }
39948
+ );
39949
+ } else {
39950
+ pending = generateOpenAIImages({
39951
+ provider: config2.provider,
39952
+ apiKey,
39953
+ prompt: input.prompt,
39954
+ signal,
39955
+ fetch: opts.fetch
39956
+ });
39957
+ }
39958
+ const response = await imageAbortable(pending, signal);
39959
+ signal.throwIfAborted();
39960
+ assertActive();
39961
+ if (response.stopReason !== "stop") {
39962
+ throw new ImageGenerationError(
39963
+ "Image provider failed or refused the request. Check OpenRouter access/quota; billing may have occurred. No automatic retry."
39964
+ );
39965
+ }
39966
+ const images = decodeImages(response, input.name ?? "generated-image");
39967
+ const responseId2 = typeof response.responseId === "string" && /^[A-Za-z0-9._:-]{1,256}$/.test(response.responseId) && !response.responseId.includes(apiKey) ? response.responseId : null;
39968
+ db.raw.transaction(() => {
39969
+ images.forEach((image2, sourceIndex) => {
39970
+ publish(db, {
39971
+ teamId: opts.teamId,
39972
+ agentId: opts.agentId,
39973
+ sessionId: input.sessionId,
39974
+ toolCallId: input.toolCallId,
39975
+ sourceIndex,
39976
+ imageModel: config2.model,
39977
+ ...image2
39978
+ });
39979
+ });
39980
+ settle2(db, op, "completed", responseId2, safeUsage(response.usage));
39981
+ })();
39982
+ return capturedOutput(op);
39983
+ } catch (error2) {
39984
+ if (signal.aborted)
39985
+ throw new Error(
39986
+ "Image generation cancelled or timed out; billing or account usage may have occurred. No automatic retry."
39987
+ );
39988
+ if (error2 instanceof ImageGenerationError) {
39989
+ throw error2;
39990
+ }
39991
+ throw new Error(
39992
+ "Image generation failed; billing or account usage may have occurred. No automatic retry or credential fallback. Check account access/quota (reconnect ChatGPT if selected), configuration and saved Results."
39993
+ );
39994
+ } finally {
39995
+ clearTimeout(timer);
39996
+ busyHomes.delete(db);
39997
+ }
39998
+ }
39999
+ };
40000
+ }
40001
+
39284
40002
  // ../daemon/src/lib/mcp/pool.ts
39285
40003
  function sanitizeName(name) {
39286
40004
  return name.replace(/[^a-zA-Z0-9_]/g, "_");
@@ -39546,9 +40264,9 @@ function verifyQuestionConsumption(paths2, question, target, turnStartEntry = 1)
39546
40264
  }
39547
40265
 
39548
40266
  // ../daemon/src/lib/question-receipt.ts
39549
- import { createHash as createHash12, createHmac, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual2 } from "crypto";
40267
+ import { createHash as createHash13, createHmac, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual2 } from "crypto";
39550
40268
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
39551
- var hash4 = (text3) => createHash12("sha256").update(text3).digest("hex");
40269
+ var hash4 = (text3) => createHash13("sha256").update(text3).digest("hex");
39552
40270
  function key(db, create8) {
39553
40271
  if (create8)
39554
40272
  db.raw.run("INSERT OR IGNORE INTO question_receipt_key (singleton, key) VALUES (1, ?)", [
@@ -39671,7 +40389,7 @@ var QuestionWaiters = class {
39671
40389
  };
39672
40390
 
39673
40391
  // ../daemon/src/lib/telegram/question-transport.ts
39674
- import { createHash as createHash14 } from "crypto";
40392
+ import { createHash as createHash15 } from "crypto";
39675
40393
 
39676
40394
  // ../daemon/src/lib/telegram/outbound-queue.ts
39677
40395
  var DEFAULT_MIN_INTERVAL_MS = Number(process.env.BAZILION_TELEGRAM_SEND_INTERVAL_MS ?? 200);
@@ -39728,7 +40446,7 @@ function sleep(ms) {
39728
40446
  }
39729
40447
 
39730
40448
  // ../daemon/src/lib/telegram/queue-binding.ts
39731
- import { createHash as createHash13 } from "crypto";
40449
+ import { createHash as createHash14 } from "crypto";
39732
40450
 
39733
40451
  // ../daemon/src/lib/telegram/ingress-attempt.ts
39734
40452
  function isTelegramIngressPayload(value) {
@@ -39814,7 +40532,7 @@ function captureTelegramQueueBinding(db, authToken, authorization, transportBotT
39814
40532
  teamId: agent.team_id,
39815
40533
  ownerGrantId: owner.grant_id,
39816
40534
  topicBindingId: agent.telegram_binding_id,
39817
- botDigest: createHash13("sha256").update(JSON.stringify([botToken, credential?.envelope ?? null])).digest("hex")
40535
+ botDigest: createHash14("sha256").update(JSON.stringify([botToken, credential?.envelope ?? null])).digest("hex")
39818
40536
  };
39819
40537
  }
39820
40538
  function requireTelegramQueueBinding(db, authToken, value) {
@@ -39978,7 +40696,7 @@ Reply to THIS message with Other text, or /answer ${question.id} your answer. Cl
39978
40696
  };
39979
40697
  }
39980
40698
  function requestId(identity2) {
39981
- const hex = createHash14("sha256").update(identity2).digest("hex");
40699
+ const hex = createHash15("sha256").update(identity2).digest("hex");
39982
40700
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-8${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
39983
40701
  }
39984
40702
  function parseTelegramQuestionReply(db, authToken, update3) {
@@ -40316,7 +41034,7 @@ async function prepareAgentDockerInputs(agent, options = {}) {
40316
41034
  skills,
40317
41035
  homeDocuments
40318
41036
  };
40319
- let image;
41037
+ let image2;
40320
41038
  let coding;
40321
41039
  try {
40322
41040
  const selection2 = resolveTeamCodingEnvironment(
@@ -40324,7 +41042,7 @@ async function prepareAgentDockerInputs(agent, options = {}) {
40324
41042
  agent.team.id,
40325
41043
  mergeSecretsIntoEnv(db, authToken)
40326
41044
  );
40327
- image = selection2.image;
41045
+ image2 = selection2.image;
40328
41046
  coding = selection2.coding;
40329
41047
  } catch {
40330
41048
  throw new ProtectedExecutionUnavailableError(
@@ -40343,7 +41061,7 @@ async function prepareAgentDockerInputs(agent, options = {}) {
40343
41061
  let docker;
40344
41062
  try {
40345
41063
  docker = await preflightProtectedDockerRuntime({
40346
- image,
41064
+ image: image2,
40347
41065
  lifecycle: options.dockerLifecycle,
40348
41066
  ...coding ? { coding } : {},
40349
41067
  workspaceDir: agent.team.path,
@@ -43424,11 +44142,41 @@ function mirrorTypingStop(agentId) {
43424
44142
  }
43425
44143
  }
43426
44144
 
44145
+ // ../daemon/src/lib/turn-tool-source.ts
44146
+ function createTurnToolSource(paths2, agent, conversation, name) {
44147
+ const initialHead = loadSessionHead(agent, paths2, conversation);
44148
+ return (sessionId, toolCallId) => {
44149
+ if (sessionId !== conversation.id || !/^[A-Za-z0-9._:-]{1,256}$/.test(toolCallId)) {
44150
+ throw new Error("Tool source does not match admitted conversation");
44151
+ }
44152
+ const head = loadSessionHead(agent, paths2, conversation);
44153
+ if (!head.file || head.size > 64 * 1024 * 1024) {
44154
+ throw new Error("Tool source session is unavailable or too large");
44155
+ }
44156
+ const entries = readResultSession(
44157
+ paths2,
44158
+ agent.agent.id,
44159
+ head.file,
44160
+ sessionId,
44161
+ initialHead.file === head.file ? initialHead.size : 0
44162
+ );
44163
+ for (const entry of entries) {
44164
+ if (entry.type !== "message" || entry.message?.role !== "assistant") continue;
44165
+ for (const block of entry.message.content) {
44166
+ if (block.type === "toolCall" && block.id === toolCallId && block.name === name) {
44167
+ return block.arguments;
44168
+ }
44169
+ }
44170
+ }
44171
+ throw new Error("Tool call is not in this turn of the canonical transcript");
44172
+ };
44173
+ }
44174
+
43427
44175
  // ../daemon/src/lib/user-md-host.ts
43428
- import { createHash as createHash15 } from "crypto";
44176
+ import { createHash as createHash16 } from "crypto";
43429
44177
  var USER_MD_MAX_BYTES = 12e3;
43430
44178
  function computeEtag(content) {
43431
- return createHash15("sha256").update(content, "utf8").digest("hex").slice(0, 16);
44179
+ return createHash16("sha256").update(content, "utf8").digest("hex").slice(0, 16);
43432
44180
  }
43433
44181
  function createDbUserMdHost(db, paths2) {
43434
44182
  return {
@@ -43501,7 +44249,7 @@ function captureVerificationRequest(db, paths2, intent, env = process.env) {
43501
44249
  );
43502
44250
  }
43503
44251
  if (intent.writablePaths && intent.writablePaths.length > 0) {
43504
- const bounded4 = [];
44252
+ const bounded5 = [];
43505
44253
  for (const path of intent.writablePaths) {
43506
44254
  if (typeof path !== "string" || path.length === 0 || path.length > 1e3) {
43507
44255
  return blocked2("unsupported", "declared writable paths are outside their bounded contract");
@@ -43516,12 +44264,12 @@ function captureVerificationRequest(db, paths2, intent, env = process.env) {
43516
44264
  `declared writable path must be inside the workspace: ${path}`
43517
44265
  );
43518
44266
  }
43519
- bounded4.push(parts.join("/"));
44267
+ bounded5.push(parts.join("/"));
43520
44268
  }
43521
- if (bounded4.length > 16) {
44269
+ if (bounded5.length > 16) {
43522
44270
  return blocked2("unsupported", "too many declared writable paths");
43523
44271
  }
43524
- environment2.writablePaths = bounded4;
44272
+ environment2.writablePaths = bounded5;
43525
44273
  }
43526
44274
  for (const check of intent.checks) {
43527
44275
  try {
@@ -43722,6 +44470,93 @@ function createVerificationRequestHost(input) {
43722
44470
  };
43723
44471
  }
43724
44472
 
44473
+ // ../daemon/src/lib/web-search.ts
44474
+ var SEARCH_TIMEOUT_MS = 15e3;
44475
+ var MAX_QUERY_CHARS = 512;
44476
+ var MAX_RESULTS = 8;
44477
+ var MAX_TITLE_CHARS = 200;
44478
+ var MAX_URL_CHARS = 2048;
44479
+ var MAX_SNIPPET_CHARS = 300;
44480
+ var WEB_SEARCH_URL_ENV = "BAZILION_WEB_SEARCH_URL";
44481
+ function webSearchBaseUrl(env = process.env) {
44482
+ const raw2 = env[WEB_SEARCH_URL_ENV]?.trim();
44483
+ if (!raw2) return null;
44484
+ let parsed;
44485
+ try {
44486
+ parsed = new URL(raw2);
44487
+ } catch {
44488
+ return null;
44489
+ }
44490
+ const loopback = parsed.hostname === "127.0.0.1" || parsed.hostname === "localhost" || parsed.hostname === "::1" || parsed.hostname === "[::1]";
44491
+ if (parsed.protocol === "https:" || parsed.protocol === "http:" && loopback) return raw2;
44492
+ return null;
44493
+ }
44494
+ function isWebSearchConfigured(env = process.env) {
44495
+ return webSearchBaseUrl(env) !== null;
44496
+ }
44497
+ var WebSearchConfigError = class extends Error {
44498
+ };
44499
+ var WebSearchBackendError = class extends Error {
44500
+ };
44501
+ function bounded3(value, max) {
44502
+ return typeof value === "string" ? value.slice(0, max) : "";
44503
+ }
44504
+ function createWebSearchHost(opts) {
44505
+ return {
44506
+ async search(args) {
44507
+ const query = typeof args?.query === "string" ? args.query.trim().slice(0, MAX_QUERY_CHARS) : "";
44508
+ if (!query) throw new WebSearchConfigError("web search: a non-empty query is required");
44509
+ const count3 = Math.min(Math.max(Number(args?.count ?? 5), 1), MAX_RESULTS);
44510
+ const baseUrl = webSearchBaseUrl(opts.env());
44511
+ if (!baseUrl) {
44512
+ throw new WebSearchConfigError(
44513
+ `No web search backend is configured. Set ${WEB_SEARCH_URL_ENV} (a self-hosted SearXNG base URL, https or loopback) or disable discovery for this turn.`
44514
+ );
44515
+ }
44516
+ const url2 = `${baseUrl.replace(/\/+$/, "")}/search?${new URLSearchParams({
44517
+ q: query,
44518
+ format: "json"
44519
+ })}`;
44520
+ let response;
44521
+ try {
44522
+ response = await fetch(url2, {
44523
+ headers: { accept: "application/json" },
44524
+ signal: AbortSignal.any([
44525
+ AbortSignal.timeout(SEARCH_TIMEOUT_MS),
44526
+ ...opts.signal ? [opts.signal] : []
44527
+ ])
44528
+ });
44529
+ } catch (error2) {
44530
+ if (opts.signal?.aborted || error2 instanceof Error && error2.name === "AbortError")
44531
+ throw new WebSearchBackendError("Web search was cancelled");
44532
+ throw new WebSearchBackendError("Web search backend is unreachable");
44533
+ }
44534
+ if (!response.ok) {
44535
+ throw new WebSearchBackendError(`Web search backend returned status ${response.status}`);
44536
+ }
44537
+ let data;
44538
+ try {
44539
+ data = await response.json();
44540
+ } catch {
44541
+ throw new WebSearchBackendError("Web search backend returned an invalid response");
44542
+ }
44543
+ const rawResults = data && typeof data === "object" ? data.results : void 0;
44544
+ if (!Array.isArray(rawResults)) {
44545
+ throw new WebSearchBackendError("Web search backend returned an invalid response");
44546
+ }
44547
+ const results = rawResults.slice(0, count3).map((item) => {
44548
+ const row2 = item;
44549
+ return {
44550
+ title: bounded3(row2.title, MAX_TITLE_CHARS),
44551
+ url: bounded3(row2.url, MAX_URL_CHARS),
44552
+ snippet: bounded3(row2.content, MAX_SNIPPET_CHARS)
44553
+ };
44554
+ });
44555
+ return { results, backend: "searxng" };
44556
+ }
44557
+ };
44558
+ }
44559
+
43725
44560
  // ../daemon/src/lib/agent-turn.ts
43726
44561
  async function* runAgentTurn(turn) {
43727
44562
  consumePreparedAgentTurn(turn);
@@ -43737,6 +44572,33 @@ async function* runAgentTurn(turn) {
43737
44572
  });
43738
44573
  const userMdHost = createDbUserMdHost(db, paths2);
43739
44574
  const resultHost = createResultHost(db, paths2, agent, turn.controller.signal, turn.conversation);
44575
+ const imageGenerationHost = imageGenerationConfig(
44576
+ mergeSecretsIntoEnv(db, authToken),
44577
+ hasCredentials(db, authToken),
44578
+ { enabledProviders: providerState_exports.listEnabled(db), chatModel: agent.model }
44579
+ ).ready ? createImageGenerationHost({
44580
+ db,
44581
+ agentId: agent.agent.id,
44582
+ teamId: agent.team.id,
44583
+ turnId,
44584
+ chatModel: agent.model,
44585
+ signal: turn.controller.signal,
44586
+ env: () => mergeSecretsIntoEnv(db, authToken),
44587
+ codex: {
44588
+ connected: () => hasCredentials(db, authToken),
44589
+ accessToken: () => loadAccessToken(db, authToken)
44590
+ },
44591
+ source: createTurnToolSource(paths2, agent, turn.conversation, "image_generate"),
44592
+ assertActive: () => {
44593
+ if (!ownsActiveAgent(agent.agent.id, turn.controller))
44594
+ throw new Error("Image generation turn ended");
44595
+ }
44596
+ }) : void 0;
44597
+ const mergedEnvSupplier = () => mergeSecretsIntoEnv(db, authToken);
44598
+ const webSearchHost = isWebSearchConfigured(mergedEnvSupplier()) ? createWebSearchHost({
44599
+ env: () => mergeSecretsIntoEnv(db, authToken),
44600
+ signal: turn.controller.signal
44601
+ }) : void 0;
43740
44602
  let contextBusy = false;
43741
44603
  const repositoryContextHost = async (target) => {
43742
44604
  turn.controller.signal.throwIfAborted();
@@ -43817,7 +44679,8 @@ async function* runAgentTurn(turn) {
43817
44679
  if (invocation.kind !== "operator_http") {
43818
44680
  throw new Error("configured operator surface requires an operator_http invocation");
43819
44681
  }
43820
- const env = mergeSecretsIntoEnv(db, authToken);
44682
+ const daemonEnv = mergeSecretsIntoEnv(db, authToken);
44683
+ const env = imageGenerationHost ? imageTurnEnv(daemonEnv, agent.model) : daemonEnv;
43821
44684
  const shellConfig = resolveShellSecurityConfig(env);
43822
44685
  const dockerEngine = turn.configuredDocker?.docker ?? (shellConfig.sandboxMode === "docker" ? await preflightProtectedDockerEngine({ image: shellConfig.sandboxImage, hostEnv: env }) : void 0);
43823
44686
  const enabledProviders = Array.from(providerState_exports.listEnabled(db));
@@ -43830,6 +44693,7 @@ async function* runAgentTurn(turn) {
43830
44693
  frames = spawnWorkerTurn(
43831
44694
  {
43832
44695
  kind: "configured_operator_http",
44696
+ imageGenerationEnabled: !!imageGenerationHost,
43833
44697
  containerNamespace,
43834
44698
  ...turn.configuredDocker ? { configuredDocker: turn.configuredDocker } : {},
43835
44699
  repositoryContext,
@@ -43856,6 +44720,7 @@ async function* runAgentTurn(turn) {
43856
44720
  verificationRequestHost,
43857
44721
  reviewRequestHost,
43858
44722
  resultHost,
44723
+ imageGenerationHost,
43859
44724
  userMdHost,
43860
44725
  browserHost,
43861
44726
  mcpHost: mcp?.host,
@@ -43875,6 +44740,8 @@ async function* runAgentTurn(turn) {
43875
44740
  frames = spawnWorkerTurn(
43876
44741
  {
43877
44742
  kind: "protected",
44743
+ imageGenerationEnabled: !!imageGenerationHost,
44744
+ webSearchEnabled: !!webSearchHost,
43878
44745
  containerNamespace,
43879
44746
  repositoryContext,
43880
44747
  agent,
@@ -43899,6 +44766,8 @@ async function* runAgentTurn(turn) {
43899
44766
  verificationRequestHost,
43900
44767
  reviewRequestHost,
43901
44768
  resultHost,
44769
+ imageGenerationHost,
44770
+ webSearchHost,
43902
44771
  userMdHost,
43903
44772
  bashApprovalHost: commandApprovalRegistry,
43904
44773
  ...questionHost ? { questionHost } : {},
@@ -44592,10 +45461,10 @@ function buildReviewDigest(input, options = {}) {
44592
45461
  }
44593
45462
  selected.reverse();
44594
45463
  const firstUserIndex = selected.findIndex((entry) => entry.role === "user");
44595
- const bounded4 = firstUserIndex >= 0 ? selected.slice(firstUserIndex) : selected;
44596
- characters = bounded4.reduce((total, entry) => total + entry.text.length, 0);
44597
- const first = bounded4[0];
44598
- const last = bounded4.at(-1);
45464
+ const bounded5 = firstUserIndex >= 0 ? selected.slice(firstUserIndex) : selected;
45465
+ characters = bounded5.reduce((total, entry) => total + entry.text.length, 0);
45466
+ const first = bounded5[0];
45467
+ const last = bounded5.at(-1);
44599
45468
  if (!first || !last) return null;
44600
45469
  return {
44601
45470
  sessionId: last.sessionId,
@@ -44603,7 +45472,7 @@ function buildReviewDigest(input, options = {}) {
44603
45472
  endOrdinal: last.ordinal,
44604
45473
  inputCharacters: characters,
44605
45474
  turnsReviewed: userTurns,
44606
- entries: bounded4
45475
+ entries: bounded5
44607
45476
  };
44608
45477
  }
44609
45478
 
@@ -45485,7 +46354,7 @@ function abandonVerificationAttempt(db, input) {
45485
46354
  }
45486
46355
 
45487
46356
  // ../daemon/src/lib/verification/writes.ts
45488
- import { createHash as createHash16 } from "crypto";
46357
+ import { createHash as createHash17 } from "crypto";
45489
46358
  import { lstat as lstat2, readdir, readFile, readlink } from "fs/promises";
45490
46359
  import { join as join29 } from "path";
45491
46360
  var FINGERPRINT_LIMITS = {
@@ -45504,7 +46373,7 @@ async function fingerprintPath(root, path, digest4) {
45504
46373
  return `link:${(await readlink(absolute)).replaceAll("\\", "/")}`;
45505
46374
  if (!info.isFile()) return `other:${info.mode}`;
45506
46375
  if (!digest4 || info.size > FINGERPRINT_LIMITS.fileBytes) return `size:${info.size}`;
45507
- return `sha256:${createHash16("sha256").update(await readFile(absolute)).digest("hex")}`;
46376
+ return `sha256:${createHash17("sha256").update(await readFile(absolute)).digest("hex")}`;
45508
46377
  }
45509
46378
  async function fingerprintWorkspace(root) {
45510
46379
  const entries = /* @__PURE__ */ new Map();
@@ -47692,7 +48561,7 @@ function errMsg(e) {
47692
48561
  }
47693
48562
 
47694
48563
  // ../daemon/src/lib/telegram/notification-transport.ts
47695
- import { createHash as createHash17 } from "crypto";
48564
+ import { createHash as createHash18 } from "crypto";
47696
48565
  var resolver = null;
47697
48566
  function notificationDestinationAllowed(chat, owner, bot) {
47698
48567
  return chat.type === "supergroup" && chat.is_forum === true && !chat.username && !chat.active_usernames?.length && owner.status !== "left" && owner.status !== "kicked" && (owner.status !== "restricted" || owner.is_member === true) && (bot.status === "creator" || bot.status === "administrator" && bot.can_manage_topics === true);
@@ -47715,8 +48584,8 @@ function capture(db, authToken) {
47715
48584
  const topicId = Number(topic?.value);
47716
48585
  if (!owner || !Number.isSafeInteger(chatId2) || chatId2 >= 0 || !Number.isSafeInteger(topicId) || topicId <= 0 || !env.TELEGRAM_BOT_TOKEN || env.TELEGRAM_BOT_TOKEN !== live2.botToken)
47717
48586
  return null;
47718
- const botDigest = createHash17("sha256").update(JSON.stringify([live2.botToken, envelope])).digest("hex");
47719
- const id = createHash17("sha256").update(JSON.stringify([chatId2, topicId, owner.grant_id, botDigest])).digest("hex");
48587
+ const botDigest = createHash18("sha256").update(JSON.stringify([live2.botToken, envelope])).digest("hex");
48588
+ const id = createHash18("sha256").update(JSON.stringify([chatId2, topicId, owner.grant_id, botDigest])).digest("hex");
47720
48589
  return {
47721
48590
  binding: { id, chatId: chatId2, topicId, ownerGrantId: owner.grant_id, botDigest },
47722
48591
  ownerId: owner.user_id,
@@ -51575,7 +52444,7 @@ communicationRouter.post("/evaluate", async (c) => {
51575
52444
  import { Hono as Hono6 } from "hono";
51576
52445
  var configRouter = new Hono6();
51577
52446
  configRouter.get("/providers", async (c) => {
51578
- const { db, paths: paths2, authToken } = getCtx();
52447
+ const { db, authToken } = getCtx();
51579
52448
  const env = mergeSecretsIntoEnv(db, authToken);
51580
52449
  const registryProviders = listAllProviders(loadProviderConfigFromEnv(env, { db, authToken }));
51581
52450
  const registryByName = new Map(registryProviders.map((p) => [p.name, p]));
@@ -51599,8 +52468,13 @@ configRouter.get("/providers", async (c) => {
51599
52468
  enabled,
51600
52469
  envHint,
51601
52470
  fields: resolveFieldStates(svc, configValues, secretValues),
51602
- catalog,
51603
- ...live2 ? { live: live2 } : {},
52471
+ catalog: catalog.filter((model) => !isImageChoice(svc.id, model)),
52472
+ ...live2 ? {
52473
+ live: {
52474
+ ...live2,
52475
+ models: live2.models.filter((model) => !isImageChoice(svc.id, model))
52476
+ }
52477
+ } : {},
51604
52478
  curated: providerModels_exports.list(db, svc.id)
51605
52479
  };
51606
52480
  } finally {
@@ -51615,7 +52489,13 @@ configRouter.get("/services", (c) => {
51615
52489
  const { db, authToken } = getCtx();
51616
52490
  const configValues = readAll(() => openConfig(db).getAll());
51617
52491
  const secretValues = readAll(() => openSecrets(db, authToken).getAll());
52492
+ const imageStatus = imageGenerationConfig(
52493
+ mergeSecretsIntoEnv(db, authToken),
52494
+ hasCredentials(db, authToken),
52495
+ { enabledProviders: providerState_exports.listEnabled(db) }
52496
+ ).status;
51618
52497
  const services3 = servicesByCategory("service").map((svc) => ({
52498
+ ...svc.id === "image-generation" ? { status: imageStatus } : {},
51619
52499
  id: svc.id,
51620
52500
  displayName: svc.displayName,
51621
52501
  ...svc.hint ? { hint: svc.hint } : {},
@@ -51662,6 +52542,12 @@ configRouter.put("/providers/:name/models", async (c) => {
51662
52542
  400
51663
52543
  );
51664
52544
  }
52545
+ if (models.some((model) => isImageChoice(name, model.trim()))) {
52546
+ return c.json(
52547
+ { error: "Configure image models in Services \u2192 Image generation, not as chat models." },
52548
+ 400
52549
+ );
52550
+ }
51665
52551
  const { db, paths: paths2 } = getCtx();
51666
52552
  providerModels_exports.replace(db, name, models);
51667
52553
  ensureSetupSeeded(db, paths2);
@@ -51675,6 +52561,9 @@ configRouter.put("/fields/:envVar", async (c) => {
51675
52561
  if (!body || typeof body.value !== "string") {
51676
52562
  return c.json({ error: 'body must be {"value": "<string>"}' }, 400);
51677
52563
  }
52564
+ if (body.value && found.field.options && !found.field.options.includes(body.value)) {
52565
+ return c.json({ error: `Choose one of: ${found.field.options.join(", ")}` }, 400);
52566
+ }
51678
52567
  const { db, authToken } = getCtx();
51679
52568
  if (found.field.kind === "config") {
51680
52569
  const store = openConfig(db);
@@ -51703,6 +52592,9 @@ configRouter.delete("/fields/:envVar", (c) => {
51703
52592
  }
51704
52593
  return c.body(null, 204);
51705
52594
  });
52595
+ function isImageChoice(provider, model) {
52596
+ return provider === "openrouter" && OPENROUTER_IMAGE_MODELS.some((id) => id === model) || (provider === "openai" || provider === "openai-codex") && model === "gpt-image-2";
52597
+ }
51706
52598
  function mask(value) {
51707
52599
  if (value.length === 0) return "";
51708
52600
  return value.length > 8 ? `${value.slice(0, 6)}\u2026` : "***";
@@ -51716,7 +52608,9 @@ function resolveFieldStates(service2, configValues, secretValues) {
51716
52608
  label: f.label,
51717
52609
  set: val.length > 0,
51718
52610
  ...f.placeholder ? { placeholder: f.placeholder } : {},
51719
- ...f.description ? { description: f.description } : {}
52611
+ ...f.description ? { description: f.description } : {},
52612
+ ...f.options ? { options: f.options } : {},
52613
+ ...f.optionLabels ? { optionLabels: f.optionLabels } : {}
51720
52614
  };
51721
52615
  if (f.kind === "config") {
51722
52616
  state3.value = val;
@@ -52009,7 +52903,7 @@ import { join as join34 } from "path";
52009
52903
  import { Hono as Hono10 } from "hono";
52010
52904
 
52011
52905
  // ../daemon/src/lib/backup.ts
52012
- import { createHash as createHash18 } from "crypto";
52906
+ import { createHash as createHash19 } from "crypto";
52013
52907
  import { mkdtempSync as mkdtempSync5, rmSync as rmSync15 } from "fs";
52014
52908
  import { tmpdir as tmpdir5 } from "os";
52015
52909
  import { join as join32, resolve as resolve7 } from "path";
@@ -52040,7 +52934,7 @@ function assertSnapshotIntegrity(path) {
52040
52934
  }
52041
52935
  for (const row2 of snapshot.prepare("SELECT id, bytes, byte_length, sha256 FROM agent_results WHERE deleted_at IS NULL").iterate()) {
52042
52936
  const bytes = row2.bytes;
52043
- if (!(bytes instanceof Uint8Array) || bytes.byteLength !== row2.byte_length || createHash18("sha256").update(bytes).digest("hex") !== row2.sha256) {
52937
+ if (!(bytes instanceof Uint8Array) || bytes.byteLength !== row2.byte_length || createHash19("sha256").update(bytes).digest("hex") !== row2.sha256) {
52044
52938
  throw new Error(`Result snapshot integrity verification failed: ${row2.id}`);
52045
52939
  }
52046
52940
  }
@@ -52108,7 +53002,7 @@ function createBackupArchive(paths2, snapshot) {
52108
53002
  }
52109
53003
 
52110
53004
  // ../daemon/src/lib/daemon-liveness.ts
52111
- import { createHash as createHash19, randomUUID as randomUUID42 } from "crypto";
53005
+ import { createHash as createHash20, randomUUID as randomUUID42 } from "crypto";
52112
53006
  import {
52113
53007
  chmodSync as chmodSync2,
52114
53008
  closeSync as closeSync10,
@@ -52140,7 +53034,7 @@ function canonicalHomeIdentity(home) {
52140
53034
  }
52141
53035
  function daemonLivenessPath(home) {
52142
53036
  const canonicalHome2 = canonicalHomeIdentity(home);
52143
- const identity2 = createHash19("sha256").update(canonicalHome2).digest("hex").slice(0, 24);
53037
+ const identity2 = createHash20("sha256").update(canonicalHome2).digest("hex").slice(0, 24);
52144
53038
  return join33(dirname8(canonicalHome2), `.bazilion-runtime-${identity2}.json`);
52145
53039
  }
52146
53040
  var activeInstanceId = null;
@@ -52236,7 +53130,7 @@ function pidIsAlive(pid) {
52236
53130
  }
52237
53131
  }
52238
53132
  function reclaimStaleRecord(path, existing) {
52239
- const identity2 = createHash19("sha256").update(existing.instanceId ?? existing.raw).update(`\0${existing.stat.dev}\0${existing.stat.ino}`).digest("hex").slice(0, 24);
53133
+ const identity2 = createHash20("sha256").update(existing.instanceId ?? existing.raw).update(`\0${existing.stat.dev}\0${existing.stat.ino}`).digest("hex").slice(0, 24);
52240
53134
  const claim5 = `${path}.reclaim-${identity2}`;
52241
53135
  try {
52242
53136
  mkdirSync11(claim5, { mode: 448 });
@@ -53728,14 +54622,14 @@ resultsRouter.get("/:id/preview", (c) => {
53728
54622
  if (!result) return c.json({ error: "Result not found" }, 404);
53729
54623
  if (result.deletedAt !== null) return c.json({ error: "This result was deleted" }, 410);
53730
54624
  const text3 = ["text/plain", "text/markdown"].includes(result.mimeType);
53731
- const image = ["image/png", "image/jpeg", "image/gif", "image/webp"].includes(result.mimeType);
53732
- if (!text3 && !image || result.byteLength > (text3 ? 256 * 1024 : 10 * 1024 * 1024)) {
54625
+ const image2 = ["image/png", "image/jpeg", "image/gif", "image/webp"].includes(result.mimeType);
54626
+ if (!text3 && !image2 || result.byteLength > (text3 ? 256 * 1024 : 10 * 1024 * 1024)) {
53733
54627
  return c.json({ error: "Preview is unavailable for this file. Use Download." }, 415);
53734
54628
  }
53735
54629
  try {
53736
54630
  const bytes = readReleased(db, result.id);
53737
54631
  const magic = result.mimeType === "image/png" ? bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) : result.mimeType === "image/jpeg" ? bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255 : result.mimeType === "image/gif" ? ["GIF87a", "GIF89a"].includes(bytes.subarray(0, 6).toString("ascii")) : result.mimeType === "image/webp" ? bytes.subarray(0, 4).toString("ascii") === "RIFF" && bytes.subarray(8, 12).toString("ascii") === "WEBP" : false;
53738
- if (image && !magic)
54632
+ if (image2 && !magic)
53739
54633
  return c.json({ error: "File content does not match its image type. Use Download." }, 415);
53740
54634
  c.header("Content-Type", text3 ? "text/plain; charset=utf-8" : result.mimeType);
53741
54635
  c.header("Content-Security-Policy", "default-src 'none'; sandbox");
@@ -54438,7 +55332,7 @@ function resolvePublicationTarget(db, authToken) {
54438
55332
  }
54439
55333
 
54440
55334
  // ../daemon/src/lib/publication/revision-content.ts
54441
- import { createHash as createHash20 } from "crypto";
55335
+ import { createHash as createHash21 } from "crypto";
54442
55336
  import { readFileSync as readFileSync15 } from "fs";
54443
55337
  import { join as join37 } from "path";
54444
55338
  function readReviewedRevisionFiles(db, paths2, packet) {
@@ -54498,7 +55392,7 @@ function readReviewedRevisionFiles(db, paths2, packet) {
54498
55392
  detail: `the reviewed content for ${entry.path} can no longer be read`
54499
55393
  };
54500
55394
  }
54501
- const digest4 = createHash20("sha256").update(content).digest("hex");
55395
+ const digest4 = createHash21("sha256").update(content).digest("hex");
54502
55396
  if (digest4 !== entry.digest) {
54503
55397
  return {
54504
55398
  ok: false,
@@ -54590,7 +55484,7 @@ async function capturePublication(db, paths2, authToken, intent) {
54590
55484
  baseBranch: target.target.baseBranch,
54591
55485
  headBranch,
54592
55486
  baseOid: packet.baseOid,
54593
- commitMessage: bounded3(commitMessage, PUBLICATION_LIMITS.commitMessage),
55487
+ commitMessage: bounded4(commitMessage, PUBLICATION_LIMITS.commitMessage),
54594
55488
  notifyAgentId: packet.requesterKind === "agent" ? packet.requesterAgentId : null
54595
55489
  });
54596
55490
  return { kind: "captured", publication };
@@ -54604,11 +55498,11 @@ async function capturePublication(db, paths2, authToken, intent) {
54604
55498
  function conclusionTitle(conclusion) {
54605
55499
  return conclusion === "changes_requested" ? "Reviewed change with requested changes" : conclusion === "recommended" ? "Reviewed change" : "Reviewed change (inconclusive review)";
54606
55500
  }
54607
- function bounded3(value, max) {
55501
+ function bounded4(value, max) {
54608
55502
  return value.length <= max ? value : `${value.slice(0, max - 1)}\u2026`;
54609
55503
  }
54610
55504
  function refused2(reason, detail3) {
54611
- return { kind: "refused", reason, detail: bounded3(detail3, PUBLICATION_LIMITS.refusalDetail) };
55505
+ return { kind: "refused", reason, detail: bounded4(detail3, PUBLICATION_LIMITS.refusalDetail) };
54612
55506
  }
54613
55507
 
54614
55508
  // ../daemon/src/lib/publication/git-publish.ts