@nekro-nxt/contracts 0.4.0 → 0.6.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 (50) hide show
  1. package/README.md +2 -0
  2. package/dist/index.mjs +3092 -164
  3. package/dist/index.mjs.map +1 -1
  4. package/lib/types/commands.d.ts +408 -0
  5. package/lib/types/commands.d.ts.map +1 -0
  6. package/lib/types/community-feedback-host.d.ts +442 -0
  7. package/lib/types/community-feedback-host.d.ts.map +1 -0
  8. package/lib/types/community-feedback.d.ts +1072 -0
  9. package/lib/types/community-feedback.d.ts.map +1 -0
  10. package/lib/types/community-personas.d.ts +4 -0
  11. package/lib/types/community-personas.d.ts.map +1 -1
  12. package/lib/types/community.d.ts +260 -13
  13. package/lib/types/community.d.ts.map +1 -1
  14. package/lib/types/config-schema.d.ts +16 -2
  15. package/lib/types/config-schema.d.ts.map +1 -1
  16. package/lib/types/credentials.d.ts +328 -0
  17. package/lib/types/credentials.d.ts.map +1 -0
  18. package/lib/types/domain.d.ts +44 -2
  19. package/lib/types/domain.d.ts.map +1 -1
  20. package/lib/types/extension-capabilities.d.ts +58 -3
  21. package/lib/types/extension-capabilities.d.ts.map +1 -1
  22. package/lib/types/extension-ui.d.ts +46 -4
  23. package/lib/types/extension-ui.d.ts.map +1 -1
  24. package/lib/types/host-api.d.ts +10805 -2887
  25. package/lib/types/host-api.d.ts.map +1 -1
  26. package/lib/types/index.d.ts +7 -0
  27. package/lib/types/index.d.ts.map +1 -1
  28. package/lib/types/linked-accounts.d.ts +100 -0
  29. package/lib/types/linked-accounts.d.ts.map +1 -0
  30. package/lib/types/logs.d.ts +355 -0
  31. package/lib/types/logs.d.ts.map +1 -0
  32. package/lib/types/response-timing.d.ts +60 -0
  33. package/lib/types/response-timing.d.ts.map +1 -0
  34. package/lib/types/runtime-compatibility.d.ts +2 -2
  35. package/package.json +1 -1
  36. package/src/commands.ts +366 -0
  37. package/src/community-feedback-host.ts +121 -0
  38. package/src/community-feedback.ts +289 -0
  39. package/src/community.ts +63 -1
  40. package/src/config-schema.ts +33 -2
  41. package/src/credentials.ts +260 -0
  42. package/src/domain.ts +74 -8
  43. package/src/extension-capabilities.ts +78 -4
  44. package/src/extension-ui.ts +3 -0
  45. package/src/host-api.ts +1873 -163
  46. package/src/index.ts +8 -0
  47. package/src/linked-accounts.ts +77 -0
  48. package/src/logs.ts +138 -0
  49. package/src/management-api.ts +1 -1
  50. package/src/response-timing.ts +77 -0
package/src/host-api.ts CHANGED
@@ -1,10 +1,44 @@
1
+ import { CommandCatalogEntrySchema, CommandExecutionRecordSchema, CommandPolicySchema } from './commands.js'
1
2
  import { z } from 'zod'
3
+ import {
4
+ hostLogDebugLeaseSchema,
5
+ hostLogDebugRequestSchema,
6
+ hostLogEntrySchema,
7
+ hostLogPageSchema,
8
+ hostLogSettingsSchema,
9
+ hostLogSourceSchema,
10
+ hostLogStatusSchema,
11
+ } from './logs.js'
2
12
  import { McpServerFormSchema } from './extension-capabilities.js'
13
+ import {
14
+ BoundCredentialsSchema,
15
+ CredentialBindingsRequestSchema,
16
+ CreateCredentialRequestSchema,
17
+ CredentialsViewSchema,
18
+ CredentialUsesViewSchema,
19
+ RemoveCredentialRequestSchema,
20
+ RemoveCredentialResultSchema,
21
+ ReplaceCredentialValueRequestSchema,
22
+ SetModelProviderAccessRequestSchema,
23
+ UpdateCredentialRequestSchema,
24
+ } from './credentials.js'
25
+ import {
26
+ AddLinkedAccountRequestSchema,
27
+ LinkedAccountMethodSchema,
28
+ LinkedAccountPlatformIdSchema,
29
+ LinkedAccountUsesViewSchema,
30
+ LinkedAccountViewSchema,
31
+ LocalGithubLoginSchema,
32
+ RemoveLinkedAccountRequestSchema,
33
+ ReplaceLinkedAccountTokenRequestSchema,
34
+ } from './linked-accounts.js'
3
35
  import { HostUpgradeSummarySchema, RuntimeCompatibilityDiagnosticSchema } from './runtime-compatibility.js'
36
+ import { AgentAliasesSchema, ResponseTimingSettingsSchema } from './response-timing.js'
4
37
  import {
5
38
  AgentIdSchema,
6
39
  AgentRevisionIdSchema,
7
40
  AuthoringAttemptIdSchema,
41
+ SubConversationIdSchema,
8
42
  AuthoringTaskIdSchema,
9
43
  AssetIdSchema,
10
44
  ChannelEventIdSchema,
@@ -12,6 +46,8 @@ import {
12
46
  ChannelIdSchema,
13
47
  ChannelMemberIdSchema,
14
48
  ConnectionIdSchema,
49
+ CredentialIdSchema,
50
+ LinkedAccountIdSchema,
15
51
  ConnectionEventIdSchema,
16
52
  DshPluginEntryIdSchema,
17
53
  DshPluginPackageIdSchema,
@@ -34,13 +70,13 @@ import {
34
70
  CommunityExtensionDetailSchema,
35
71
  CommunityExtensionSummarySchema,
36
72
  CommunityExtensionSortSchema,
73
+ CommunityFreshnessSchema,
37
74
  CommunityListingInputSchema,
38
75
  CommunityReleaseIdSchema,
39
76
  CommunityReviewStatusSchema,
40
77
  CommunityStatusSchema,
41
- CommunitySourceSchema,
42
78
  CommunityEndpointSchema,
43
- CommunityInstalledSchema,
79
+ CommunitySyncSchema,
44
80
  CommunityMyExtensionSchema,
45
81
  CommunityReviewReportSchema,
46
82
  } from './community.js'
@@ -101,6 +137,9 @@ const DynamicAttemptErrorSchema = z
101
137
  phase: z.enum(['approval', 'host-load', 'host-apply', 'client-load', 'client-apply', 'client-render']),
102
138
  message: z.string(),
103
139
  stack: z.string().optional(),
140
+ /** A render failure also names the contribution slot that failed and whether its frame gave up. */
141
+ slot: NonEmptyStringSchema.optional(),
142
+ abdicated: z.boolean().optional(),
104
143
  pluginId: DynamicIdSchema,
105
144
  packageId: DynamicIdSchema,
106
145
  pluginRunId: DynamicIdSchema,
@@ -131,6 +170,7 @@ const AuthoringTaskStatusSchema = z.enum([
131
170
  'interrupted',
132
171
  'stopped',
133
172
  'completed',
173
+ 'paused',
134
174
  ])
135
175
 
136
176
  const AuthoringAttemptStateSchema = z.enum([
@@ -175,6 +215,8 @@ const AuthoringAttemptSummarySchema = z
175
215
  })
176
216
  .strict()
177
217
  .optional(),
218
+ /** Verified without loading its interface, because no browser was available; the interface itself is unchecked. */
219
+ uiUnverified: z.boolean().optional(),
178
220
  createdAt: z.number().int().nonnegative(),
179
221
  settledAt: z.number().int().nonnegative().optional(),
180
222
  })
@@ -189,6 +231,15 @@ const AuthoringTaskSummarySchema = z
189
231
  title: z.string(),
190
232
  requirementSummary: z.string(),
191
233
  status: AuthoringTaskStatusSchema,
234
+ /** `create` builds a new extension; `revise` changes `targetExtensionId` starting from `baseRevisionId`. */
235
+ kind: z.enum(['create', 'revise']).default('create'),
236
+ targetExtensionId: ExtensionIdSchema.optional(),
237
+ baseRevisionId: ExtensionRevisionIdSchema.optional(),
238
+ referenceRevisionId: ExtensionRevisionIdSchema.optional(),
239
+ /** Why the task is paused; it continues when the agent picks it up in a later conversation. */
240
+ pausedReason: z.string().optional(),
241
+ /** The conversation the task runs in is live, so its candidate can be previewed directly. */
242
+ live: z.boolean().default(false),
192
243
  approvalPolicy: z.enum(['risk-stable', 'fully-automatic']),
193
244
  approvedRiskDigest: z
194
245
  .string()
@@ -282,6 +333,23 @@ export const ImageUnderstandingPolicyApiSchema = z
282
333
  })
283
334
  .strict()
284
335
 
336
+ export const CommandAccountUsageSchema = z.enum(['read', 'issues', 'pull-requests', 'push'])
337
+ /** What the user wants a granted account used for; told to the agent only. */
338
+ export type CommandAccountUsage = z.output<typeof CommandAccountUsageSchema>
339
+
340
+ /**
341
+ * One linked account the agent's commands act as, at most one per platform (`service`). Grants saved before linked
342
+ * accounts name the account without its `acc_` prefix; both forms resolve to the same account.
343
+ */
344
+ const CommandAccountGrantSchema = z
345
+ .object({
346
+ service: LinkedAccountPlatformIdSchema,
347
+ accountId: NonEmptyStringSchema.max(72),
348
+ /** Told to the agent as guidance, not enforced; empty gives no hint. */
349
+ usage: z.array(CommandAccountUsageSchema).max(4).default([]),
350
+ })
351
+ .strict()
352
+
285
353
  const AgentCapabilitiesSchema = z
286
354
  .object({
287
355
  subagents: z.boolean(),
@@ -296,12 +364,33 @@ const AgentCapabilitiesSchema = z
296
364
  codeRun: z.boolean().default(false),
297
365
  /** Network for commands; absent in older clients means on. */
298
366
  commandNetwork: z.boolean().default(true),
367
+ communityFeedbackAuto: z.boolean().default(false),
368
+ /** Linked accounts this agent's commands act as, one per platform; absent in older clients means none. */
369
+ commandAccounts: z.array(CommandAccountGrantSchema).max(8).default([]),
370
+ /**
371
+ * What the agent may do with extensions without the console: `manual` only develops and test-runs, `confirm` asks
372
+ * an administrator in the channel for every step, `autonomous` takes ordinary steps that only affect itself.
373
+ */
374
+ extensionAutonomy: z.enum(['manual', 'confirm', 'autonomous']).default('manual'),
375
+ /** Whose requests make the agent develop or change extensions: anyone in the channel, or administrators only. */
376
+ extensionRequesters: z.enum(['everyone', 'admins']).default('everyone'),
377
+ /**
378
+ * Whose requests make the agent change extension configuration. With `everyone`, members may only have it change
379
+ * ordinary fields of its own configuration; network fields, the host layer and credentials still need an
380
+ * administrator.
381
+ */
382
+ extensionConfigRequesters: z.enum(['everyone', 'admins']).default('admins'),
299
383
  })
300
384
  .strict()
301
385
 
302
386
  export const DynamicClientApprovalPolicySchema = z.enum(['manual', 'automatic'])
303
387
 
304
- export const NotificationEventKeySchema = z.enum(['dynamic-client-approval-requested'])
388
+ export const NotificationEventKeySchema = z.enum([
389
+ 'dynamic-client-approval-requested',
390
+ 'community-feedback-update',
391
+ 'credential-requested',
392
+ 'extension-notification',
393
+ ])
305
394
  export type NotificationEventKey = z.output<typeof NotificationEventKeySchema>
306
395
 
307
396
  export const NotificationSettingsViewSchema = z
@@ -315,7 +404,14 @@ export const NotificationSettingsViewSchema = z
315
404
  deviceKeyConfigured: z.boolean(),
316
405
  })
317
406
  .strict(),
318
- events: z.record(NotificationEventKeySchema, z.boolean()),
407
+ events: z
408
+ .object({
409
+ 'dynamic-client-approval-requested': z.boolean(),
410
+ 'community-feedback-update': z.boolean().default(true),
411
+ 'credential-requested': z.boolean().default(true),
412
+ 'extension-notification': z.boolean().default(true),
413
+ })
414
+ .strict(),
319
415
  })
320
416
  .strict()
321
417
 
@@ -331,7 +427,14 @@ export const UpdateNotificationSettingsRequestSchema = z
331
427
  clearDeviceKey: z.boolean().optional(),
332
428
  })
333
429
  .strict(),
334
- events: z.record(NotificationEventKeySchema, z.boolean()),
430
+ events: z
431
+ .object({
432
+ 'dynamic-client-approval-requested': z.boolean(),
433
+ 'community-feedback-update': z.boolean().optional(),
434
+ 'credential-requested': z.boolean().optional(),
435
+ 'extension-notification': z.boolean().optional(),
436
+ })
437
+ .strict(),
335
438
  })
336
439
  .strict()
337
440
  .refine((value) => !(value.bark.deviceKey !== undefined && value.bark.clearDeviceKey === true), {
@@ -350,6 +453,122 @@ export const ClientNotificationFeedResponseSchema = z
350
453
  })
351
454
  .strict()
352
455
 
456
+ /** Which model writes one kind of compaction summary: that kind's default, or a model chosen for this agent. */
457
+ export const AgentCompactionModelChoiceSchema = z.discriminatedUnion('mode', [
458
+ z.object({ mode: z.literal('follow') }).strict(),
459
+ z.object({ mode: z.literal('custom'), model: AgentModelSchema }).strict(),
460
+ ])
461
+
462
+ /**
463
+ * In-session compaction follows the main model by default, so the replayed conversation hits the provider's cache;
464
+ * compaction into a new session follows the host's compaction model.
465
+ */
466
+ export const AgentCompactionPolicySchema = z
467
+ .object({ inSession: AgentCompactionModelChoiceSchema, newSession: AgentCompactionModelChoiceSchema })
468
+ .strict()
469
+
470
+ /** The host's idle compaction threshold, summary model and wait limit. */
471
+ export const CompactionSettingsSchema = z
472
+ .object({
473
+ /** Minimum context occupancy for idle rollover; older settings inherit 50%. */
474
+ idleThresholdPercent: z.number().int().min(1).max(100).default(50),
475
+ newSessionModel: z.discriminatedUnion('mode', [
476
+ z.object({ mode: z.literal('main') }).strict(),
477
+ z.object({ mode: z.literal('custom'), model: AgentModelSchema }).strict(),
478
+ ]),
479
+ /** Past this the new session starts with a fallback note instead of a summary. */
480
+ timeoutSeconds: z.number().int().min(30).max(900),
481
+ })
482
+ .strict()
483
+
484
+ export type CompactionSettings = z.output<typeof CompactionSettingsSchema>
485
+
486
+ export const DEFAULT_COMPACTION_SETTINGS: CompactionSettings = {
487
+ idleThresholdPercent: 50,
488
+ newSessionModel: { mode: 'main' },
489
+ timeoutSeconds: 180,
490
+ }
491
+
492
+ export const FALLBACK_MODEL_LIMIT = 3
493
+
494
+ /**
495
+ * Models an agent switches to, in order, when its main model has used up its quota or stays unavailable after the
496
+ * usual retries. Empty leaves the main model alone, as before fallback models existed.
497
+ */
498
+ export const AgentFallbackModelsSchema = z
499
+ .array(AgentModelSchema)
500
+ .max(FALLBACK_MODEL_LIMIT)
501
+ .refine(
502
+ (models) => new Set(models.map((model) => `${model.provider}\0${model.model}`)).size === models.length,
503
+ '备用模型不能重复。',
504
+ )
505
+
506
+ /** Why a channel conversation left its main model. */
507
+ export const ModelFallbackReasonSchema = z.enum(['quota', 'rate-limit', 'unavailable'])
508
+ export type ModelFallbackReason = z.output<typeof ModelFallbackReasonSchema>
509
+
510
+ /** How long a model that failed is passed over before conversations try it again. */
511
+ export const ModelFallbackSettingsSchema = z
512
+ .object({
513
+ /** After rate limits, server errors, timeouts or empty replies that outlasted the usual retries. */
514
+ unavailableCooldownMinutes: z.number().int().min(1).max(240),
515
+ /** After the quota or balance ran out. */
516
+ quotaCooldownMinutes: z.number().int().min(5).max(1440),
517
+ })
518
+ .strict()
519
+
520
+ export type ModelFallbackSettings = z.output<typeof ModelFallbackSettingsSchema>
521
+
522
+ export const DEFAULT_MODEL_FALLBACK_SETTINGS: ModelFallbackSettings = {
523
+ unavailableCooldownMinutes: 10,
524
+ quotaCooldownMinutes: 60,
525
+ }
526
+
527
+ /** The name an agent passes to open a sub-conversation on its main model; no candidate may take it. */
528
+ export const SUB_CONVERSATION_MAIN_MODEL = '主模型'
529
+
530
+ export const SUB_CONVERSATION_MODEL_LIMITS = { candidates: 8, name: 20, guidance: 200 } as const
531
+
532
+ /**
533
+ * Models an agent may open sub-conversations with, each named so the agent can pick it and described so it knows
534
+ * when to. Without a `default`, a sub-conversation opened without naming a model follows the main model.
535
+ */
536
+ export const AgentSubConversationModelsSchema = z
537
+ .object({
538
+ candidates: z
539
+ .array(
540
+ z
541
+ .object({
542
+ // Names are listed to the agent separated by commas, so they carry none and no line breaks.
543
+ name: z
544
+ .string()
545
+ .trim()
546
+ .min(1, '请填写子对话模型的名称。')
547
+ .max(SUB_CONVERSATION_MODEL_LIMITS.name)
548
+ .regex(/^[^\s,,、]+(?: [^\s,,、]+)*$/u, '子对话模型的名称不能含换行、逗号或顿号。')
549
+ .refine((name) => name !== SUB_CONVERSATION_MAIN_MODEL, `「${SUB_CONVERSATION_MAIN_MODEL}」是保留名称。`),
550
+ model: AgentModelSchema,
551
+ guidance: z.string().trim().max(SUB_CONVERSATION_MODEL_LIMITS.guidance),
552
+ })
553
+ .strict(),
554
+ )
555
+ .max(SUB_CONVERSATION_MODEL_LIMITS.candidates),
556
+ default: z.string().trim().min(1).optional(),
557
+ })
558
+ .strict()
559
+ .superRefine((policy, context) => {
560
+ const names = policy.candidates.map((candidate) => candidate.name)
561
+ if (new Set(names).size !== names.length)
562
+ context.addIssue({ code: 'custom', message: '子对话模型的名称不能重复。' })
563
+ if (policy.default !== undefined && !names.includes(policy.default)) {
564
+ context.addIssue({ code: 'custom', message: '默认的子对话模型不在候选里。' })
565
+ }
566
+ })
567
+
568
+ export type AgentSubConversationModels = z.output<typeof AgentSubConversationModelsSchema>
569
+
570
+ export const NO_SUB_CONVERSATION_MODELS: AgentSubConversationModels = { candidates: [] }
571
+
353
572
  const AgentRevisionRequestContentSchema = z
354
573
  .object({
355
574
  displayName: z.string().trim().min(1).max(80),
@@ -361,6 +580,10 @@ const AgentRevisionRequestContentSchema = z
361
580
  model: AgentModelSchema,
362
581
  imagePolicy: ImageUnderstandingPolicyApiSchema.optional(),
363
582
  dynamicClientApprovalPolicy: DynamicClientApprovalPolicySchema.optional(),
583
+ compaction: AgentCompactionPolicySchema.optional(),
584
+ subConversationModels: AgentSubConversationModelsSchema.optional(),
585
+ fallbackModels: AgentFallbackModelsSchema.optional(),
586
+ aliases: AgentAliasesSchema.optional(),
364
587
  })
365
588
  .strict()
366
589
 
@@ -390,18 +613,23 @@ const ReviseAgentRequestSchema = AgentRevisionRequestContentSchema.extend({
390
613
  validatePersonaDocumentProjection(value, context)
391
614
  })
392
615
 
393
- // The defaults that fill `scheduledTasks`, `codeRun` and `commandNetwork` for older clients must not reset them in a
394
- // partial update.
616
+ // Defaults that fill capabilities for older clients must not
617
+ // reset them in a partial update.
395
618
  const UpdateAgentCapabilitiesRequestSchema = AgentCapabilitiesSchema.partial()
396
619
  .extend({
397
620
  scheduledTasks: z.boolean().optional(),
398
621
  codeRun: z.boolean().optional(),
399
622
  commandNetwork: z.boolean().optional(),
623
+ communityFeedbackAuto: z.boolean().optional(),
624
+ commandAccounts: z.array(CommandAccountGrantSchema).max(8).optional(),
625
+ extensionAutonomy: z.enum(['manual', 'confirm', 'autonomous']).optional(),
626
+ extensionRequesters: z.enum(['everyone', 'admins']).optional(),
627
+ extensionConfigRequesters: z.enum(['everyone', 'admins']).optional(),
400
628
  })
401
629
  .strict()
402
630
  .refine((value) => Object.values(value).some((entry) => entry !== undefined), '至少提供一个能力。')
403
631
 
404
- const TriggerPolicySchema = z.enum(['always', 'mentioned-or-replied', 'command', 'observe-only'])
632
+ const TriggerPolicySchema = z.enum(['always', 'mentioned-or-replied', 'smart', 'command', 'observe-only'])
405
633
 
406
634
  export const WorkTreeOrderSchema = z
407
635
  .object({
@@ -413,12 +641,35 @@ export const WorkTreeOrderSchema = z
413
641
 
414
642
  export type WorkTreeOrder = z.output<typeof WorkTreeOrderSchema>
415
643
 
644
+ /** The group key of 「未接线」 in `collapsedGroupIds`; agent groups use the agent id. */
645
+ export const UNBOUND_CHANNEL_GROUP_ID = 'unbound'
646
+
647
+ /**
648
+ * How the console arranges its channel list: pinned channels in their order and the groups it has collapsed. Shared
649
+ * by every device signed in to the console; it never changes bindings.
650
+ */
651
+ export const ChannelListViewSchema = z
652
+ .object({
653
+ pinnedChannelIds: z.array(ChannelIdSchema).max(200),
654
+ collapsedGroupIds: z.array(z.union([AgentIdSchema, z.literal(UNBOUND_CHANNEL_GROUP_ID)])).max(500),
655
+ })
656
+ .strict()
657
+
658
+ export type ChannelListView = z.output<typeof ChannelListViewSchema>
659
+
416
660
  const SnapshotMessagePartSchema = z.discriminatedUnion('type', [
417
661
  z.object({ type: z.literal('text'), text: z.string() }).strict(),
418
662
  z
419
663
  .object({ type: z.literal('mention'), memberId: ChannelMemberIdSchema, displayName: z.string().optional() })
420
664
  .strict(),
421
- z.object({ type: z.literal('image'), assetId: AssetIdSchema, alt: z.string().optional() }).strict(),
665
+ z
666
+ .object({
667
+ type: z.literal('image'),
668
+ assetId: AssetIdSchema,
669
+ alt: z.string().optional(),
670
+ sticker: z.literal(true).optional(),
671
+ })
672
+ .strict(),
422
673
  z.object({ type: z.literal('file'), assetId: AssetIdSchema, name: z.string().optional() }).strict(),
423
674
  z.object({ type: z.literal('audio'), assetId: AssetIdSchema }).strict(),
424
675
  z.object({ type: z.literal('quote'), messageId: LogicalMessageIdSchema }).strict(),
@@ -465,7 +716,10 @@ export const HostSnapshotMessageSchema = z
465
716
  })
466
717
  .strict()
467
718
  .optional(),
468
- origin: z.enum(['admin-console']).optional(),
719
+ origin: z.enum(['admin-console', 'command', 'extension-notice']).optional(),
720
+ command: CommandExecutionRecordSchema.optional(),
721
+ /** A host notice about extension work: a request an administrator must confirm, or what an action did. */
722
+ extensionNotice: z.object({ requestNumber: z.number().int().positive().optional() }).strict().optional(),
469
723
  /** What the agent's inbound hooks decided for this message, when anything differs from the default. */
470
724
  inboundHook: z
471
725
  .object({
@@ -477,11 +731,29 @@ export const HostSnapshotMessageSchema = z
477
731
  })
478
732
  .strict()
479
733
  .optional(),
734
+ /** Extensions that processed the agent's message before it was sent; `followUp` marks a message one appended. */
735
+ outboundProcessing: z
736
+ .object({
737
+ extensions: z.array(z.string()),
738
+ rewritten: z.boolean(),
739
+ followUp: z.literal(true).optional(),
740
+ })
741
+ .strict()
742
+ .optional(),
480
743
  /** A scheduled task came due: a Host fact shown as a notice, not a member message. */
481
744
  scheduledTask: z
482
745
  .object({ label: z.string(), extensionName: z.string().optional(), note: z.string().optional() })
483
746
  .strict()
484
747
  .optional(),
748
+ /** The agent finished waiting for someone to finish speaking: a Host fact shown as a notice. */
749
+ responseWait: z
750
+ .object({
751
+ displayName: z.string().optional(),
752
+ cause: z.enum(['quiet', 'limit']),
753
+ waitedSeconds: z.number().int().nonnegative(),
754
+ })
755
+ .strict()
756
+ .optional(),
485
757
  })
486
758
  .strict()
487
759
 
@@ -535,6 +807,8 @@ export const PlatformUserListResponseSchema = z
535
807
  activeChannelCount: z.number().int().nonnegative(),
536
808
  channelPreview: z.array(PlatformUserChannelPreviewSchema).max(3),
537
809
  historicalOnly: z.boolean(),
810
+ /** Listed in Settings → Administrators. */
811
+ administrator: z.boolean().default(false),
538
812
  })
539
813
  .strict(),
540
814
  ),
@@ -566,7 +840,14 @@ export const ChannelFactSseDataSchema = z
566
840
  })
567
841
  .strict()
568
842
 
569
- export const ChannelRuntimePhaseSchema = z.enum(['idle', 'thinking', 'using-tool', 'waiting-input', 'unavailable'])
843
+ export const ChannelRuntimePhaseSchema = z.enum([
844
+ 'idle',
845
+ 'thinking',
846
+ 'using-tool',
847
+ 'compacting',
848
+ 'waiting-input',
849
+ 'unavailable',
850
+ ])
570
851
 
571
852
  export const ChannelRuntimeUsageSchema = z
572
853
  .object({
@@ -587,7 +868,8 @@ const channelRuntimeToolFields = {
587
868
  inputPreview: z.string().optional(),
588
869
  resultPreview: z.string().optional(),
589
870
  wroteToChannel: z.boolean().optional(),
590
- deliveryState: z.enum(['sent', 'partially-sent', 'failed', 'unknown']).optional(),
871
+ /** `cancelled`: an extension stopped the message before it was sent. */
872
+ deliveryState: z.enum(['sent', 'partially-sent', 'failed', 'unknown', 'cancelled']).optional(),
591
873
  durationMs: z.number().int().nonnegative().optional(),
592
874
  }
593
875
 
@@ -796,6 +1078,21 @@ export const ChannelRuntimeProjectionSchema = z
796
1078
  episodeId: EpisodeIdSchema.optional(),
797
1079
  phase: ChannelRuntimePhaseSchema,
798
1080
  summary: z.string(),
1081
+ /** A compaction under way: inside the current session, or before a new session opens. */
1082
+ compaction: z
1083
+ .object({ kind: z.enum(['in-session', 'new-session']), startedAt: z.number().int().nonnegative() })
1084
+ .strict()
1085
+ .optional(),
1086
+ /** The conversation runs on a fallback model; it tries the main model again at a new message after `retryMainAt`. */
1087
+ modelFallback: z
1088
+ .object({
1089
+ model: AgentModelSchema,
1090
+ reason: ModelFallbackReasonSchema,
1091
+ since: z.number().int().nonnegative(),
1092
+ retryMainAt: z.number().int().nonnegative(),
1093
+ })
1094
+ .strict()
1095
+ .optional(),
799
1096
  pendingInjectCount: z.number().int().nonnegative(),
800
1097
  occupancy: ChannelRuntimeOccupancySchema.optional(),
801
1098
  cache: ChannelRuntimeCacheSchema.optional(),
@@ -945,6 +1242,42 @@ export const DEFAULT_MESSAGE_PACING: MessagePacing = 'normal'
945
1242
 
946
1243
  export const MessagePacingSettingsSchema = z.object({ pacing: MessagePacingSchema }).strict()
947
1244
 
1245
+ /**
1246
+ * A conversation of its own under a channel's conversation (docs/NekroNxt界面交互模型.md §5.6): the agent opens one
1247
+ * for a separate piece of work, and the host opens scripted ones to check creation candidates. It has its own log
1248
+ * and context, and is shown under its channel.
1249
+ */
1250
+ export const SubConversationSchema = z
1251
+ .object({
1252
+ id: SubConversationIdSchema,
1253
+ channelId: ChannelIdSchema,
1254
+ episodeId: EpisodeIdSchema,
1255
+ agentId: AgentIdSchema,
1256
+ title: z.string().min(1).max(200),
1257
+ /** `agent`: the agent opened it with a tool; `host`: NekroNXT opened it, such as to check a candidate. */
1258
+ openedBy: z.enum(['agent', 'host']),
1259
+ /** `model`: the agent's model talks in it; `script`: the host plays fixed tool calls. */
1260
+ driver: z.enum(['model', 'script']),
1261
+ status: z.enum(['open', 'closed']),
1262
+ closeReason: z.enum(['completed', 'closed-by-agent', 'closed-by-admin', 'failed', 'conversation-ended']).optional(),
1263
+ /** What it handed back to the channel's conversation when it ended. */
1264
+ summary: z.string().max(4000).optional(),
1265
+ authoringTaskId: AuthoringTaskIdSchema.optional(),
1266
+ /** The model a model-driven sub-conversation talks in; absent for scripts and ones opened before it was kept. */
1267
+ model: AgentModelSchema.optional(),
1268
+ createdAt: z.number().int().nonnegative(),
1269
+ closedAt: z.number().int().nonnegative().optional(),
1270
+ })
1271
+ .strict()
1272
+
1273
+ export type SubConversation = z.output<typeof SubConversationSchema>
1274
+
1275
+ /** How long ended sub-conversations are kept before they are cleaned up. */
1276
+ export const SubConversationRetentionSchema = z.enum(['1d', '3d', '7d', '30d', 'never'])
1277
+ export type SubConversationRetention = z.output<typeof SubConversationRetentionSchema>
1278
+ export const DEFAULT_SUB_CONVERSATION_RETENTION: SubConversationRetention = '7d'
1279
+ export const SubConversationSettingsSchema = z.object({ retention: SubConversationRetentionSchema }).strict()
1280
+
948
1281
  /** `keyword`: SQLite keyword search only; `builtin`: keywords fused with the built-in semantic model. */
949
1282
  export const RetrievalModeSchema = z.enum(['keyword', 'builtin'])
950
1283
  export type RetrievalMode = z.output<typeof RetrievalModeSchema>
@@ -985,6 +1318,23 @@ export const RetrievalStatusSchema = z
985
1318
  .strict()
986
1319
  export type RetrievalStatus = z.output<typeof RetrievalStatusSchema>
987
1320
 
1321
+ /** Where the Host keeps restore points it takes before an upgrade, or none. */
1322
+ export const UpgradeBackupModeSchema = z.enum(['data', 'directory', 'off'])
1323
+ export const UpgradeBackupSettingsSchema = z
1324
+ .object({
1325
+ mode: UpgradeBackupModeSchema,
1326
+ /** The chosen directory when `mode` is `directory`. */
1327
+ directory: z.string().nullable(),
1328
+ /** Set through the server's environment; the settings page cannot change it. */
1329
+ locked: z.boolean(),
1330
+ /** Restore points kept; older ones are removed after an upgrade succeeds. */
1331
+ keep: z.number().int().positive(),
1332
+ /** Restore points currently in the chosen place. */
1333
+ usage: z.object({ count: z.number().int().nonnegative(), bytes: z.number().int().nonnegative() }).strict(),
1334
+ })
1335
+ .strict()
1336
+ export type UpgradeBackupSettings = z.output<typeof UpgradeBackupSettingsSchema>
1337
+
988
1338
  /** What the agent keeps about individual members of one channel; each note comes with that member's messages. */
989
1339
  export const ChannelMemberNotesViewSchema = z
990
1340
  .object({
@@ -1145,11 +1495,23 @@ export const AttentionItemSchema = z
1145
1495
  'connection-unhealthy',
1146
1496
  'agent-model-unavailable',
1147
1497
  'agent-vision-unavailable',
1498
+ 'logs-unavailable',
1499
+ 'community-feedback',
1500
+ 'extension-update',
1148
1501
  ]),
1149
1502
  severity: z.enum(['critical', 'warning', 'info']),
1150
1503
  subject: z
1151
1504
  .object({
1152
- kind: z.enum(['outbound', 'channel', 'authoring-task', 'connection', 'agent']),
1505
+ kind: z.enum([
1506
+ 'outbound',
1507
+ 'channel',
1508
+ 'authoring-task',
1509
+ 'connection',
1510
+ 'agent',
1511
+ 'logs',
1512
+ 'community-feedback',
1513
+ 'extension-update',
1514
+ ]),
1153
1515
  id: NonEmptyStringSchema,
1154
1516
  })
1155
1517
  .strict(),
@@ -1166,7 +1528,16 @@ export const AttentionItemSchema = z
1166
1528
  detail: z.string().max(400),
1167
1529
  action: z
1168
1530
  .object({
1169
- kind: z.enum(['open-channel', 'resolve-delivery', 'open-authoring-task', 'open-connection', 'open-agent']),
1531
+ kind: z.enum([
1532
+ 'open-channel',
1533
+ 'resolve-delivery',
1534
+ 'open-authoring-task',
1535
+ 'open-connection',
1536
+ 'open-agent',
1537
+ 'open-logs',
1538
+ 'open-community-feedback',
1539
+ 'open-extension-updates',
1540
+ ]),
1170
1541
  label: z.string().min(1).max(40),
1171
1542
  })
1172
1543
  .strict(),
@@ -1311,8 +1682,73 @@ export const CodeRunAvailabilitySchema = z
1311
1682
 
1312
1683
  export type CodeRunAvailability = z.output<typeof CodeRunAvailabilitySchema>
1313
1684
 
1685
+ /** The GitHub CLI commands call: found on this machine, or downloaded by NekroNXT where it can. */
1686
+ export const GithubCliAvailabilitySchema = CodeRunAvailabilitySchema
1687
+ export type GithubCliAvailability = z.output<typeof GithubCliAvailabilitySchema>
1688
+
1689
+ /** The optional headless Chromium that loads and checks creation candidates when no page is open. */
1690
+ export const VerificationBrowserAvailabilitySchema = CodeRunAvailabilitySchema
1691
+ export type VerificationBrowserAvailability = z.output<typeof VerificationBrowserAvailabilitySchema>
1692
+
1693
+ /** A platform's own program that linked accounts work through, such as the GitHub CLI. */
1694
+ export const LinkedAccountPlatformToolSchema = z
1695
+ .object({
1696
+ /** The runtime download routes it is managed by (`downloadGithubCli`, `removeGithubCli`). */
1697
+ id: z.enum(['github-cli']),
1698
+ name: z.string(),
1699
+ availability: GithubCliAvailabilitySchema,
1700
+ })
1701
+ .strict()
1702
+
1703
+ /** 设置 → 关联账号: every platform the host supports, with its accounts and tools. */
1704
+ export const LinkedAccountsViewSchema = z
1705
+ .object({
1706
+ platforms: z.array(
1707
+ z
1708
+ .object({
1709
+ id: LinkedAccountPlatformIdSchema,
1710
+ name: z.string(),
1711
+ addMethods: z.array(LinkedAccountMethodSchema),
1712
+ tool: LinkedAccountPlatformToolSchema.optional(),
1713
+ accounts: z.array(LinkedAccountViewSchema),
1714
+ })
1715
+ .strict(),
1716
+ ),
1717
+ /** Logins found in the local GitHub CLI; empty when it is missing or not logged in. */
1718
+ localGithubLogins: z.array(LocalGithubLoginSchema),
1719
+ })
1720
+ .strict()
1721
+ export type LinkedAccountsView = z.output<typeof LinkedAccountsViewSchema>
1722
+
1723
+ export const RemoveLinkedAccountResultSchema = z.discriminatedUnion('removed', [
1724
+ z.object({ removed: z.literal(true), view: LinkedAccountsViewSchema }).strict(),
1725
+ z.object({ removed: z.literal(false), grantedAgentIds: z.array(AgentIdSchema) }).strict(),
1726
+ ])
1727
+ export type RemoveLinkedAccountResult = z.output<typeof RemoveLinkedAccountResultSchema>
1728
+
1729
+ /** An extension action an agent asked an administrator to confirm, or one it took on its own. */
1730
+ export const ExtensionRequestSchema = z
1731
+ .object({
1732
+ number: z.number().int().positive(),
1733
+ kind: z.string(),
1734
+ agentId: AgentIdSchema,
1735
+ channelId: ChannelIdSchema.nullable(),
1736
+ extensionId: ExtensionIdSchema.nullable(),
1737
+ summary: z.string(),
1738
+ status: z.enum(['pending', 'approved', 'rejected', 'expired', 'completed', 'failed']),
1739
+ autonomous: z.boolean(),
1740
+ resultMessage: z.string().nullable(),
1741
+ decidedBy: z.string().nullable(),
1742
+ createdAt: z.number().int().nonnegative(),
1743
+ expiresAt: z.number().int().nonnegative(),
1744
+ decidedAt: z.number().int().nonnegative().nullable(),
1745
+ })
1746
+ .strict()
1747
+ export type ExtensionRequestView = z.output<typeof ExtensionRequestSchema>
1748
+
1314
1749
  export const HostSnapshotSchema = z
1315
1750
  .object({
1751
+ communityFeedback: CommunityFeedbackSnapshotSchema.optional(),
1316
1752
  upgrade: HostUpgradeSummarySchema.optional(),
1317
1753
  cursor: HostSyncCursorSchema,
1318
1754
  diagnosticsSampledAt: z.number().int().nonnegative(),
@@ -1337,6 +1773,14 @@ export const HostSnapshotSchema = z
1337
1773
  name: z.string(),
1338
1774
  description: z.string().optional(),
1339
1775
  inputModalities: z.array(z.string()).optional(),
1776
+ /** Selectable thinking levels, least to most; absent when the model offers no choice. */
1777
+ reasoning: z
1778
+ .object({
1779
+ efforts: z.array(z.object({ id: NonEmptyStringSchema, name: z.string() }).strict()).min(1),
1780
+ defaultEffort: NonEmptyStringSchema.optional(),
1781
+ })
1782
+ .strict()
1783
+ .optional(),
1340
1784
  })
1341
1785
  .strict(),
1342
1786
  ),
@@ -1345,10 +1789,15 @@ export const HostSnapshotSchema = z
1345
1789
  subagents: z.object({ available: z.boolean() }).strict(),
1346
1790
  /** Optional in older hosts, which never offer `run_code`. */
1347
1791
  codeRun: CodeRunAvailabilitySchema.optional(),
1792
+ /** Optional in older hosts, which never offer command accounts. */
1793
+ githubCli: GithubCliAvailabilitySchema.optional(),
1794
+ /** Optional in older hosts, which check candidates only in an open page. */
1795
+ verificationBrowser: VerificationBrowserAvailabilitySchema.optional(),
1348
1796
  /** What this host can confine for commands beyond file writes; optional in older hosts. */
1349
1797
  commandConfinement: z.object({ readScope: z.boolean(), networkControl: z.boolean() }).strict().optional(),
1350
1798
  webSearch: z
1351
1799
  .object({
1800
+ unavailableReason: z.string().optional(),
1352
1801
  provider: z.literal('deepseek-official'),
1353
1802
  available: z.boolean(),
1354
1803
  credentialConfigured: z.boolean(),
@@ -1373,6 +1822,19 @@ export const HostSnapshotSchema = z
1373
1822
  capabilities: AgentCapabilitiesSchema,
1374
1823
  imagePolicy: ImageUnderstandingPolicyApiSchema,
1375
1824
  dynamicClientApprovalPolicy: DynamicClientApprovalPolicySchema,
1825
+ /** Optional for older hosts, whose agents always follow both defaults. */
1826
+ compaction: AgentCompactionPolicySchema.optional(),
1827
+ /** Optional for older hosts, whose agents offer no candidates. */
1828
+ subConversationModels: AgentSubConversationModelsSchema.optional(),
1829
+ /** Optional for older hosts, whose agents have no fallback models. */
1830
+ fallbackModels: AgentFallbackModelsSchema.optional(),
1831
+ /** Optional for older hosts, whose agents have no aliases. */
1832
+ aliases: AgentAliasesSchema.optional(),
1833
+ /**
1834
+ * Enabled extensions that process the agent's messages before they are sent, in the order they run. Absent
1835
+ * when none does.
1836
+ */
1837
+ outboundOrder: z.array(ExtensionIdSchema).optional(),
1376
1838
  imageDiagnostics: z
1377
1839
  .object({
1378
1840
  route: z
@@ -1427,6 +1889,8 @@ export const HostSnapshotSchema = z
1427
1889
  platformChannelId: NonEmptyStringSchema,
1428
1890
  kind: z.enum(['internal', 'group', 'direct']),
1429
1891
  displayName: z.string().optional(),
1892
+ localDisplayName: z.string().optional(),
1893
+ platformDisplayName: z.string().optional(),
1430
1894
  boundAgentId: AgentIdSchema.optional(),
1431
1895
  runtimePhase: ChannelRuntimePhaseSchema.default('idle'),
1432
1896
  activity: ChannelActivitySummarySchema.default({ unreadCount: 0, unreadCapped: false }),
@@ -1438,10 +1902,14 @@ export const HostSnapshotSchema = z
1438
1902
  channelId: ChannelIdSchema,
1439
1903
  agentId: AgentIdSchema,
1440
1904
  triggerPolicy: TriggerPolicySchema,
1905
+ /** Channel pause, independent of the response rule. */
1906
+ paused: z.boolean().default(false),
1441
1907
  processingFeedback: z.enum(['auto', 'off']).default('auto'),
1442
1908
  /** Absent means `observe`. */
1443
1909
  localAgentMessages: z.enum(['observe', 'trigger']).optional(),
1444
1910
  activityTriggerOverrides: ActivityTriggerOverridesSchema.default({}),
1911
+ /** Absent on older hosts; missing keys use the defaults. */
1912
+ responseTiming: ResponseTimingSettingsSchema.optional(),
1445
1913
  boundAt: z.number().int().safe().nonnegative(),
1446
1914
  })
1447
1915
  .strict(),
@@ -1454,6 +1922,7 @@ export const HostSnapshotSchema = z
1454
1922
  channelIdsByAgent: {},
1455
1923
  unboundChannelIds: [],
1456
1924
  }),
1925
+ channelListView: ChannelListViewSchema.default({ pinnedChannelIds: [], collapsedGroupIds: [] }),
1457
1926
  messages: z.array(HostSnapshotMessageSchema),
1458
1927
  connections: z.array(
1459
1928
  z
@@ -1462,6 +1931,8 @@ export const HostSnapshotSchema = z
1462
1931
  adapterKey: NonEmptyStringSchema,
1463
1932
  alias: ConnectionAliasOutputSchema.optional(),
1464
1933
  activityTriggerDefaults: z.array(AdapterActivityKeySchema).default([]),
1934
+ configuredSecrets: z.array(z.string()).optional(),
1935
+ boundCredentials: BoundCredentialsSchema.optional(),
1465
1936
  status: z
1466
1937
  .object({
1467
1938
  state: z.enum(['stopped', 'connecting', 'connected', 'reconnecting', 'failed']),
@@ -1526,11 +1997,50 @@ export const HostSnapshotSchema = z
1526
1997
  displayName: z.string(),
1527
1998
  description: z.string(),
1528
1999
  createdByAgentId: AgentIdSchema.optional(),
2000
+ /** The Revision of another extension this one was branched from. */
2001
+ branchOf: z
2002
+ .object({
2003
+ extensionId: ExtensionIdSchema,
2004
+ revisionId: ExtensionRevisionIdSchema,
2005
+ /** Present while the original is on this machine. */
2006
+ displayName: z.string().optional(),
2007
+ })
2008
+ .strict()
2009
+ .optional(),
2010
+ /** Shape version of the data stored on this machine. */
2011
+ dataVersion: z.number().int().positive().default(1),
2012
+ /** The unfinished revise task of this extension, if any. */
2013
+ openRevisionTaskId: AuthoringTaskIdSchema.optional(),
2014
+ /** Whether this machine publishes (`owner`) or follows the line on each community. */
2015
+ communityLinks: z
2016
+ .array(z.object({ communityUrl: z.string(), role: z.enum(['owner', 'subscriber']) }).strict())
2017
+ .default([]),
1529
2018
  revisions: z.array(
1530
2019
  z
1531
2020
  .object({
1532
2021
  id: ExtensionRevisionIdSchema,
1533
2022
  revisionNumber: z.number().int().positive(),
2023
+ /** Version number from the lineage, `v3` (or `v3·2` for a second Revision of the same generation). */
2024
+ versionLabel: z.string(),
2025
+ parentRevisionId: ExtensionRevisionIdSchema.optional(),
2026
+ origin: z.enum(['authored', 'file', 'community', 'branch']),
2027
+ authoringTaskId: AuthoringTaskIdSchema.optional(),
2028
+ dataVersion: z.number().int().positive(),
2029
+ /** Community releases this Revision is; installs and publishes from here both record one. */
2030
+ releases: z
2031
+ .array(
2032
+ z
2033
+ .object({
2034
+ communityUrl: z.string(),
2035
+ releaseId: CommunityReleaseIdSchema,
2036
+ number: z.number().int().positive().nullable(),
2037
+ publisherHandle: z.string(),
2038
+ via: z.enum(['install', 'publish']),
2039
+ recordedAt: z.number().int().nonnegative(),
2040
+ })
2041
+ .strict(),
2042
+ )
2043
+ .default([]),
1534
2044
  format: z.enum(['current', 'unavailable']).optional(),
1535
2045
  ui: ExtensionUiContributionsSchema.default(EMPTY_EXTENSION_UI_CONTRIBUTIONS),
1536
2046
  /** The host instance's configuration form (`config.host`). */
@@ -1543,8 +2053,6 @@ export const HostSnapshotSchema = z
1543
2053
  .regex(/^\/api\/extensions\/[^/]+\/revisions\/[^/]+\/icon\/[a-f0-9]{64}\.(?:svg|png|webp)$/u)
1544
2054
  .optional(),
1545
2055
  createdAt: z.number().int().safe().nonnegative(),
1546
- /** 从社区安装的版本的来源;本机保存与文件导入没有来源。 */
1547
- source: CommunitySourceSchema.optional(),
1548
2056
  provides: z.array(ExtensionProvideSchema),
1549
2057
  /** Whether this Revision can be enabled for agents (agent-layer contributions or capabilities). */
1550
2058
  agentLayer: z.boolean(),
@@ -1597,6 +2105,7 @@ export const HostSnapshotSchema = z
1597
2105
  /** Secret fields are removed; `configuredSecrets` lists those the Host stores. */
1598
2106
  config: JsonValueSchema,
1599
2107
  configuredSecrets: z.array(z.string()).optional(),
2108
+ boundCredentials: BoundCredentialsSchema.optional(),
1600
2109
  activatedAt: z.number().int().safe().nonnegative(),
1601
2110
  runtime: z
1602
2111
  .object({
@@ -1632,6 +2141,7 @@ export const HostSnapshotSchema = z
1632
2141
  /** Secret fields are removed; `configuredSecrets` lists those the Host stores. */
1633
2142
  config: JsonValueSchema.default({}),
1634
2143
  configuredSecrets: z.array(z.string()).optional(),
2144
+ boundCredentials: BoundCredentialsSchema.optional(),
1635
2145
  runtime: z
1636
2146
  .object({
1637
2147
  status: z.enum(['active', 'restore-failed', 'dispose-failed']),
@@ -1712,18 +2222,36 @@ export const HostSnapshotSchema = z
1712
2222
  .strict(),
1713
2223
  ),
1714
2224
  authoringTasks: z.array(AuthoringTaskSummarySchema).default([]),
2225
+ /** Open sub-conversations, and the most recently ended ones of each channel. */
2226
+ subConversations: z.array(SubConversationSchema).default([]),
1715
2227
  scheduledTasks: z.array(ScheduledTaskSchema).default([]),
2228
+ /** Extension requests waiting for an administrator. */
2229
+ extensionRequests: z.array(ExtensionRequestSchema).default([]),
1716
2230
  })
1717
2231
  .strict()
1718
2232
 
2233
+ export const CHANNEL_COMPOSER_MAX_ATTACHMENTS = 20
2234
+ export const CHANNEL_COMPOSER_MAX_BYTES = 64 * 1024 * 1024
2235
+
1719
2236
  const MessageInputPartSchema = z.discriminatedUnion('type', [
1720
2237
  z.object({ type: z.literal('text'), text: z.string().trim().min(1) }).strict(),
1721
2238
  z.object({ type: z.literal('mention'), memberId: ChannelMemberIdSchema }).strict(),
2239
+ z.object({ type: z.literal('image'), assetId: AssetIdSchema, alt: z.string().trim().max(500).optional() }).strict(),
2240
+ z.object({ type: z.literal('file'), assetId: AssetIdSchema, name: z.string().trim().max(255).optional() }).strict(),
1722
2241
  ])
1723
2242
 
1724
2243
  const SendChannelMessageRequestSchema = z
1725
2244
  .object({
1726
- parts: z.array(MessageInputPartSchema).min(1),
2245
+ parts: z
2246
+ .array(MessageInputPartSchema)
2247
+ .min(1)
2248
+ .max(256)
2249
+ .refine(
2250
+ (parts) =>
2251
+ parts.filter((part) => part.type === 'image' || part.type === 'file').length <=
2252
+ CHANNEL_COMPOSER_MAX_ATTACHMENTS,
2253
+ '每条消息最多添加 20 个附件。',
2254
+ ),
1727
2255
  clientEventId: NonEmptyStringSchema.optional(),
1728
2256
  senderMemberId: ChannelMemberIdSchema.optional(),
1729
2257
  })
@@ -1822,6 +2350,8 @@ export const DshPluginCatalogEntrySchema = z
1822
2350
  loadError: z.object({ code: NonEmptyStringSchema, message: NonEmptyStringSchema }).strict().optional(),
1823
2351
  packageId: DshPluginPackageIdSchema.optional(),
1824
2352
  installSource: z.enum(['registry', 'tarball', 'imported']).optional(),
2353
+ /** Published by the DSH maintainers on npm for the DSH release this build runs. */
2354
+ official: z.boolean().optional(),
1825
2355
  installedAt: z.number().int().safe().nonnegative().optional(),
1826
2356
  clientUiDetected: z.boolean().optional(),
1827
2357
  hostUi: DshNxtHostUiSchema.optional(),
@@ -1836,6 +2366,8 @@ export const DshPluginCatalogEntrySchema = z
1836
2366
  suggestedScope: z.enum(['host', 'agent']),
1837
2367
  selectedScope: z.enum(['host', 'agent']).optional(),
1838
2368
  config: JsonValueSchema,
2369
+ /** Host services this official entry declared and received; known once it has loaded. */
2370
+ grantedServices: z.array(NonEmptyStringSchema).optional(),
1839
2371
  activations: z.array(
1840
2372
  z
1841
2373
  .object({
@@ -1845,9 +2377,13 @@ export const DshPluginCatalogEntrySchema = z
1845
2377
  activatedAt: z.number().int().safe().nonnegative(),
1846
2378
  diagnostic: z
1847
2379
  .object({
1848
- status: z.enum(['active', 'load-failed', 'restore-failed', 'dispose-failed']),
1849
- phase: z.enum(['import', 'apply', 'update', 'dispose', 'restore']),
2380
+ status: z.enum(['active', 'pending', 'load-failed', 'restore-failed', 'dispose-failed']),
2381
+ phase: z.enum(['import', 'dependency', 'apply', 'update', 'dispose', 'restore']),
1850
2382
  message: z.string().optional(),
2383
+ /** Services a pending entry still waits for. */
2384
+ waitingFor: z.array(NonEmptyStringSchema).optional(),
2385
+ /** The waited-for services this entry can never receive, since only official plugins get them. */
2386
+ restrictedServices: z.array(NonEmptyStringSchema).optional(),
1851
2387
  observedAt: z.number().int().safe().nonnegative(),
1852
2388
  })
1853
2389
  .optional(),
@@ -1962,6 +2498,9 @@ export type HostSseEvent = z.output<typeof HostSseEventSchema>
1962
2498
  /** Request content a model accepts; `image` enables native vision for agents using the model. */
1963
2499
  export const LlmModelInputModalitiesSchema = z.array(z.enum(['text', 'image'])).min(1)
1964
2500
 
2501
+ /** Thinking levels a model offers, least to most; the ids are the adapter's own. */
2502
+ export const LlmModelReasoningEffortsSchema = z.array(NonEmptyStringSchema).min(1)
2503
+
1965
2504
  export const LlmProviderModelSchema = z
1966
2505
  .object({
1967
2506
  id: NonEmptyStringSchema,
@@ -1969,6 +2508,7 @@ export const LlmProviderModelSchema = z
1969
2508
  contextWindow: z.number().int().positive().optional(),
1970
2509
  maxTokens: z.number().int().positive().optional(),
1971
2510
  inputModalities: LlmModelInputModalitiesSchema.optional(),
2511
+ reasoningEfforts: LlmModelReasoningEffortsSchema.optional(),
1972
2512
  })
1973
2513
  .strict()
1974
2514
 
@@ -1979,6 +2519,7 @@ export const LlmDiscoveredModelSchema = z
1979
2519
  contextWindow: z.number().int().positive().optional(),
1980
2520
  maxTokens: z.number().int().positive().optional(),
1981
2521
  inputModalities: LlmModelInputModalitiesSchema.optional(),
2522
+ reasoningEfforts: LlmModelReasoningEffortsSchema.optional(),
1982
2523
  })
1983
2524
  .strict()
1984
2525
 
@@ -2022,6 +2563,60 @@ export const LlmProviderViewSchema = z
2022
2563
  discoverable: z.boolean(),
2023
2564
  /** `null` when the current configuration was never tested; absent from hosts that do not record tests. */
2024
2565
  lastTest: LlmProviderTestResultSchema.nullable().optional(),
2566
+ /** Present when the provider can sign in with a subscription account instead of an API key. */
2567
+ subscription: z
2568
+ .object({
2569
+ label: NonEmptyStringSchema,
2570
+ /** The route uses the signed-in account rather than an API key. */
2571
+ active: z.boolean(),
2572
+ accountLabel: z.string().nullable(),
2573
+ })
2574
+ .strict()
2575
+ .optional(),
2576
+ })
2577
+ .strict()
2578
+
2579
+ export const SubscriptionStatusSchema = z
2580
+ .object({
2581
+ provider: NonEmptyStringSchema,
2582
+ label: NonEmptyStringSchema,
2583
+ usageUrl: z.url(),
2584
+ available: z.boolean(),
2585
+ mode: z.enum(['unconfigured', 'api-key', 'subscription']),
2586
+ activeAccountId: z.string().nullable(),
2587
+ accounts: z.array(
2588
+ z
2589
+ .object({
2590
+ id: NonEmptyStringSchema,
2591
+ label: NonEmptyStringSchema,
2592
+ email: z.string().nullable(),
2593
+ createdAt: z.number().int().nonnegative(),
2594
+ })
2595
+ .strict(),
2596
+ ),
2597
+ login: z
2598
+ .object({
2599
+ id: NonEmptyStringSchema,
2600
+ status: z.enum(['running', 'authorized', 'cancelled', 'failed']),
2601
+ notices: z.array(
2602
+ z.object({ message: z.string(), url: z.string().optional(), code: z.string().optional() }).strict(),
2603
+ ),
2604
+ prompt: z
2605
+ .object({
2606
+ id: NonEmptyStringSchema,
2607
+ kind: z.enum(['text', 'secret', 'select']),
2608
+ message: z.string(),
2609
+ placeholder: z.string().optional(),
2610
+ options: z
2611
+ .array(z.object({ id: z.string(), label: z.string(), description: z.string().optional() }).strict())
2612
+ .optional(),
2613
+ })
2614
+ .strict()
2615
+ .nullable(),
2616
+ error: z.string().nullable(),
2617
+ })
2618
+ .strict()
2619
+ .nullable(),
2025
2620
  })
2026
2621
  .strict()
2027
2622
 
@@ -2126,6 +2721,8 @@ const defineContract = <
2126
2721
  })
2127
2722
 
2128
2723
  const agentParam = z.object({ agentId: AgentIdSchema }).strict()
2724
+ const credentialParam = z.object({ credentialId: CredentialIdSchema }).strict()
2725
+ const linkedAccountParam = z.object({ accountId: LinkedAccountIdSchema }).strict()
2129
2726
  const agentRevisionParam = z.object({ agentId: AgentIdSchema, revisionId: AgentRevisionIdSchema }).strict()
2130
2727
 
2131
2728
  export const AgentRevisionChangedFieldSchema = z.enum([
@@ -2135,6 +2732,10 @@ export const AgentRevisionChangedFieldSchema = z.enum([
2135
2732
  'capabilities',
2136
2733
  'imagePolicy',
2137
2734
  'approvalPolicy',
2735
+ 'compaction',
2736
+ 'subConversationModels',
2737
+ 'fallbackModels',
2738
+ 'aliases',
2138
2739
  ])
2139
2740
 
2140
2741
  export const AgentRevisionHistorySchema = z
@@ -2163,75 +2764,419 @@ const connectionParam = z.object({ connectionId: ConnectionIdSchema }).strict()
2163
2764
  const agentExtensionParam = z.object({ agentId: AgentIdSchema, extensionId: ExtensionIdSchema }).strict()
2164
2765
 
2165
2766
  const PermissionApprovalSchema = z.object({ permissionDigest: z.string().regex(/^[a-f0-9]{64}$/u) }).strict()
2166
- const extensionParam = z.object({ extensionId: ExtensionIdSchema }).strict()
2167
- const dshPluginPackageParam = z.object({ packageId: DshPluginPackageIdSchema }).strict()
2168
- const dshPluginEntryParam = z.object({ entryId: DshPluginEntryIdSchema }).strict()
2169
- const extensionRevisionParam = z
2170
- .object({ extensionId: ExtensionIdSchema, revisionId: ExtensionRevisionIdSchema })
2767
+
2768
+ /** One version of one line in the lineage view of an extension family. */
2769
+ export const ExtensionLineageNodeSchema = z
2770
+ .object({
2771
+ revisionId: ExtensionRevisionIdSchema,
2772
+ extensionId: ExtensionIdSchema,
2773
+ label: z.string(),
2774
+ parentRevisionId: ExtensionRevisionIdSchema.optional(),
2775
+ origin: z.enum(['authored', 'file', 'community', 'branch']),
2776
+ createdAt: z.number().int().nonnegative(),
2777
+ current: z.boolean(),
2778
+ releaseNumbers: z.array(z.number().int().positive()),
2779
+ })
2171
2780
  .strict()
2172
- const dshSettingsParam = z.object({ namespace: NonEmptyStringSchema }).strict()
2173
- const dshCredentialParam = z.object({ ref: DshCredentialRefSchema }).strict()
2174
- const llmProviderParam = z.object({ provider: NonEmptyStringSchema }).strict()
2175
- const authoringTaskParam = z.object({ taskId: AuthoringTaskIdSchema }).strict()
2176
- const scheduledTaskParam = z.object({ taskId: ScheduledTaskIdSchema }).strict()
2177
- const authoringAttemptParam = z.object({ taskId: AuthoringTaskIdSchema, attemptId: AuthoringAttemptIdSchema }).strict()
2178
2781
 
2179
- const DshPluginInstallInspectionSchema = z
2782
+ /** Every line of the family an extension belongs to: the original and every branch of a branch on this machine. */
2783
+ export const ExtensionLineageSchema = z
2180
2784
  .object({
2181
- token: NonEmptyStringSchema,
2182
- operationId: z.string().uuid().optional(),
2183
- packageName: NonEmptyStringSchema,
2184
- packageVersion: NonEmptyStringSchema,
2185
- packageDigest: z.string().regex(/^[a-f0-9]{64}$/u),
2186
- lockfileDigest: z.string().regex(/^[a-f0-9]{64}$/u),
2187
- blockedBuilds: z.array(NonEmptyStringSchema),
2188
- clientUiDetected: z.boolean(),
2189
- hostUi: DshNxtHostUiSchema.optional(),
2190
- entries: z.array(
2785
+ lines: z.array(
2191
2786
  z
2192
2787
  .object({
2193
- entryKey: NonEmptyStringSchema,
2194
- moduleName: NonEmptyStringSchema,
2195
- suggestedScope: z.enum(['host', 'agent']),
2788
+ extensionId: ExtensionIdSchema,
2789
+ displayName: z.string(),
2790
+ branchOf: z
2791
+ .object({ extensionId: ExtensionIdSchema, revisionId: ExtensionRevisionIdSchema })
2792
+ .strict()
2793
+ .optional(),
2794
+ nodes: z.array(ExtensionLineageNodeSchema),
2196
2795
  })
2197
2796
  .strict(),
2198
2797
  ),
2199
2798
  })
2200
2799
  .strict()
2201
2800
 
2202
- const BinaryUploadRequestSchema = z
2801
+ const DataChangeCountSchema = z
2203
2802
  .object({
2204
- bytes: z.instanceof(Uint8Array),
2205
- fileName: z.string().max(255).optional(),
2206
- operationId: z.string().uuid().optional(),
2803
+ added: z.number().int().nonnegative(),
2804
+ overwritten: z.number().int().nonnegative(),
2805
+ removed: z.number().int().nonnegative(),
2806
+ unchanged: z.number().int().nonnegative(),
2207
2807
  })
2208
2808
  .strict()
2209
- const encodeBinaryUpload = (input: z.output<typeof BinaryUploadRequestSchema>) => ({
2210
- body: input.bytes,
2211
- headers: {
2212
- 'content-type': 'application/octet-stream',
2213
- ...(input.fileName === undefined ? {} : { 'x-file-name': input.fileName }),
2214
- ...(input.operationId === undefined ? {} : { 'x-operation-id': input.operationId }),
2215
- },
2216
- })
2217
2809
 
2218
- export const HostApiContracts = {
2219
- retryRuntimeCompatibility: defineContract({
2220
- method: 'POST',
2221
- path: '/api/runtime/compatibility/retry',
2222
- params: EmptyParamsSchema,
2223
- request: z
2224
- .object({ objectKind: RuntimeCompatibilityDiagnosticSchema.shape.objectKind, objectId: z.string().min(1) })
2810
+ /** Where a data migration takes data from. */
2811
+ export const ExtensionDataSourceSchema = z.discriminatedUnion('kind', [
2812
+ z.object({ kind: z.literal('extension'), extensionId: ExtensionIdSchema }).strict(),
2813
+ z.object({ kind: z.literal('snapshot'), snapshotId: z.string().min(1).max(80) }).strict(),
2814
+ z.object({ kind: z.literal('package'), token: z.string().min(1).max(80) }).strict(),
2815
+ ])
2816
+
2817
+ export const ExtensionDataMigrationInputSchema = z
2818
+ .object({
2819
+ source: ExtensionDataSourceSchema,
2820
+ mode: z.enum(['overwrite', 'replace']),
2821
+ /** Storage of a source agent goes to the mapped agent here; unmapped agents are skipped. */
2822
+ agentMap: z.record(z.string(), AgentIdSchema).optional(),
2823
+ /** Also move the host and agent configuration (never credentials) the same way. */
2824
+ includeConfig: z.boolean().optional(),
2825
+ })
2826
+ .strict()
2827
+
2828
+ export const ExtensionDataPreviewSchema = z
2829
+ .object({
2830
+ diff: z
2831
+ .object({ storage: DataChangeCountSchema, index: DataChangeCountSchema, library: DataChangeCountSchema })
2225
2832
  .strict(),
2226
- response: z.object({ diagnostics: z.array(RuntimeCompatibilityDiagnosticSchema) }).strict(),
2227
- error: HostApiErrorSchema,
2228
- invalidatesSnapshot: true,
2229
- }),
2230
- snapshot: defineContract({
2231
- method: 'GET',
2232
- path: '/api/snapshot',
2233
- params: EmptyParamsSchema,
2234
- request: NoRequestBodySchema,
2833
+ destructive: z.boolean(),
2834
+ sourceDataVersion: z.number().int().positive(),
2835
+ targetDataVersion: z.number().int().positive(),
2836
+ needsMigration: z.boolean(),
2837
+ /** Configuration fields that would change, when configuration moves too. */
2838
+ config: z
2839
+ .object({
2840
+ hostFields: z.array(z.string()),
2841
+ agents: z.array(z.object({ agentId: AgentIdSchema, fields: z.array(z.string()) }).strict()),
2842
+ })
2843
+ .strict()
2844
+ .optional(),
2845
+ })
2846
+ .strict()
2847
+
2848
+ export const ExtensionDataStateSchema = z
2849
+ .object({
2850
+ dataVersion: z.number().int().positive(),
2851
+ counts: z
2852
+ .object({
2853
+ storage: z.number().int().nonnegative(),
2854
+ index: z.number().int().nonnegative(),
2855
+ library: z.number().int().nonnegative(),
2856
+ })
2857
+ .strict(),
2858
+ snapshots: z.array(
2859
+ z
2860
+ .object({
2861
+ id: z.string(),
2862
+ reason: z.enum(['switch', 'migration', 'manual']),
2863
+ label: z.string(),
2864
+ dataVersion: z.number().int().positive(),
2865
+ byteSize: z.number().int().nonnegative(),
2866
+ createdAt: z.number().int().nonnegative(),
2867
+ })
2868
+ .strict(),
2869
+ ),
2870
+ })
2871
+ .strict()
2872
+
2873
+ export const ExtensionDataPackageInspectionSchema = z
2874
+ .object({
2875
+ token: z.string(),
2876
+ extensionId: z.string(),
2877
+ displayName: z.string(),
2878
+ dataVersion: z.number().int().positive(),
2879
+ exportedAt: z.number().int().nonnegative(),
2880
+ agents: z.array(z.object({ id: z.string(), name: z.string() }).strict()),
2881
+ counts: z
2882
+ .object({
2883
+ storage: z.number().int().nonnegative(),
2884
+ index: z.number().int().nonnegative(),
2885
+ library: z.number().int().nonnegative(),
2886
+ })
2887
+ .strict(),
2888
+ })
2889
+ .strict()
2890
+
2891
+ export const AdministratorSchema = z
2892
+ .object({
2893
+ connectionId: ConnectionIdSchema,
2894
+ connectionName: z.string(),
2895
+ platformUserId: z.string(),
2896
+ identityId: PlatformIdentityIdSchema.optional(),
2897
+ displayName: z.string(),
2898
+ addedVia: z.enum(['console', 'claim']),
2899
+ addedAt: z.number().int().nonnegative(),
2900
+ })
2901
+ .strict()
2902
+
2903
+ const extensionParam = z.object({ extensionId: ExtensionIdSchema }).strict()
2904
+
2905
+ export const ExtensionConfigVersionSourceSchema = z.enum(['console', 'agent', 'chat-admin', 'revert', 'auto-revert'])
2906
+ export type ExtensionConfigVersionSource = z.output<typeof ExtensionConfigVersionSourceSchema>
2907
+
2908
+ /**
2909
+ * One saved state of an extension's host configuration or of one agent's configuration. Versions are numbered per
2910
+ * extension, layer and agent; reverting writes an old one again as a new version. Secret fields only show whether
2911
+ * they were set and which named credential they were bound to.
2912
+ */
2913
+ export const ExtensionConfigVersionSchema = z
2914
+ .object({
2915
+ id: z.number().int().positive(),
2916
+ extensionId: ExtensionIdSchema,
2917
+ layer: z.enum(['host', 'agent']),
2918
+ agentId: AgentIdSchema.nullable(),
2919
+ version: z.number().int().positive(),
2920
+ config: JsonValueSchema,
2921
+ configuredSecrets: z.array(z.string()).optional(),
2922
+ boundCredentials: z.record(z.string(), CredentialIdSchema).optional(),
2923
+ source: ExtensionConfigVersionSourceSchema,
2924
+ actorAgentId: AgentIdSchema.nullable(),
2925
+ requesterMemberId: z.string().nullable(),
2926
+ reason: z.string().nullable(),
2927
+ createdAt: z.number().int().nonnegative(),
2928
+ })
2929
+ .strict()
2930
+ export type ExtensionConfigVersion = z.output<typeof ExtensionConfigVersionSchema>
2931
+
2932
+ const extensionConfigVersionParam = z
2933
+ .object({
2934
+ extensionId: ExtensionIdSchema,
2935
+ /** Decimal text of the version id; the path builder only takes strings. */
2936
+ versionId: z.string().regex(/^[1-9]\d{0,15}$/u),
2937
+ })
2938
+ .strict()
2939
+ const dshPluginPackageParam = z.object({ packageId: DshPluginPackageIdSchema }).strict()
2940
+ const dshPluginEntryParam = z.object({ entryId: DshPluginEntryIdSchema }).strict()
2941
+ const extensionRevisionParam = z
2942
+ .object({ extensionId: ExtensionIdSchema, revisionId: ExtensionRevisionIdSchema })
2943
+ .strict()
2944
+ const dshSettingsParam = z.object({ namespace: NonEmptyStringSchema }).strict()
2945
+ const dshCredentialParam = z.object({ ref: DshCredentialRefSchema }).strict()
2946
+ const llmProviderParam = z.object({ provider: NonEmptyStringSchema }).strict()
2947
+ const authoringTaskParam = z.object({ taskId: AuthoringTaskIdSchema }).strict()
2948
+ const subConversationParam = z.object({ conversationId: SubConversationIdSchema }).strict()
2949
+ const scheduledTaskParam = z.object({ taskId: ScheduledTaskIdSchema }).strict()
2950
+ const authoringAttemptParam = z.object({ taskId: AuthoringTaskIdSchema, attemptId: AuthoringAttemptIdSchema }).strict()
2951
+
2952
+ const DshPluginInstallInspectionSchema = z
2953
+ .object({
2954
+ token: NonEmptyStringSchema,
2955
+ operationId: z.string().uuid().optional(),
2956
+ packageName: NonEmptyStringSchema,
2957
+ packageVersion: NonEmptyStringSchema,
2958
+ packageDigest: z.string().regex(/^[a-f0-9]{64}$/u),
2959
+ lockfileDigest: z.string().regex(/^[a-f0-9]{64}$/u),
2960
+ blockedBuilds: z.array(NonEmptyStringSchema),
2961
+ clientUiDetected: z.boolean(),
2962
+ hostUi: DshNxtHostUiSchema.optional(),
2963
+ entries: z.array(
2964
+ z
2965
+ .object({
2966
+ entryKey: NonEmptyStringSchema,
2967
+ moduleName: NonEmptyStringSchema,
2968
+ suggestedScope: z.enum(['host', 'agent']),
2969
+ })
2970
+ .strict(),
2971
+ ),
2972
+ })
2973
+ .strict()
2974
+
2975
+ const BinaryUploadRequestSchema = z
2976
+ .object({
2977
+ bytes: z.instanceof(Uint8Array),
2978
+ fileName: z.string().max(255).optional(),
2979
+ operationId: z.string().uuid().optional(),
2980
+ })
2981
+ .strict()
2982
+ const encodeBinaryUpload = (input: z.output<typeof BinaryUploadRequestSchema>) => ({
2983
+ body: input.bytes,
2984
+ headers: {
2985
+ 'content-type': 'application/octet-stream',
2986
+ ...(input.fileName === undefined ? {} : { 'x-file-name': input.fileName }),
2987
+ ...(input.operationId === undefined ? {} : { 'x-operation-id': input.operationId }),
2988
+ },
2989
+ })
2990
+
2991
+ export const HostApiContracts = {
2992
+ listCommands: defineContract({
2993
+ method: 'GET',
2994
+ path: '/api/commands',
2995
+ params: z.object({ channelId: ChannelIdSchema.optional() }).strict(),
2996
+ request: NoRequestBodySchema,
2997
+ response: z
2998
+ .object({
2999
+ commands: z.array(CommandCatalogEntrySchema),
3000
+ problems: z.array(z.string()),
3001
+ /** Host-wide behavior: whether platform members without a grant are told so. */
3002
+ settings: z.object({ unauthorizedFeedback: z.boolean() }).strict(),
3003
+ /** Present when a channel was requested. */
3004
+ channel: z
3005
+ .object({
3006
+ kind: z.enum(['internal', 'direct', 'group']),
3007
+ /** The channel is an external group where commands must address the account. */
3008
+ requiresMention: z.boolean(),
3009
+ bareCommands: z.boolean(),
3010
+ })
3011
+ .strict()
3012
+ .optional(),
3013
+ })
3014
+ .strict(),
3015
+ error: HostApiErrorSchema,
3016
+ }),
3017
+ executeCommand: defineContract({
3018
+ method: 'POST',
3019
+ path: '/api/commands/execute',
3020
+ params: EmptyParamsSchema,
3021
+ request: z
3022
+ .object({ channelId: ChannelIdSchema, text: z.string().min(1).max(16000), requestId: z.string().min(1).max(200) })
3023
+ .strict(),
3024
+ response: CommandExecutionRecordSchema,
3025
+ error: HostApiErrorSchema,
3026
+ invalidatesSnapshot: true,
3027
+ }),
3028
+ getCommandExecution: defineContract({
3029
+ method: 'GET',
3030
+ path: '/api/commands/executions/:executionId',
3031
+ params: z.object({ executionId: z.string().min(1) }).strict(),
3032
+ request: NoRequestBodySchema,
3033
+ response: CommandExecutionRecordSchema,
3034
+ error: HostApiErrorSchema,
3035
+ }),
3036
+ setCommandPolicy: defineContract({
3037
+ method: 'PUT',
3038
+ path: '/api/commands/policy',
3039
+ params: EmptyParamsSchema,
3040
+ request: z
3041
+ .object({
3042
+ scope: z.union([z.literal('global'), ChannelIdSchema]),
3043
+ name: z.string().min(1),
3044
+ policy: CommandPolicySchema,
3045
+ })
3046
+ .strict(),
3047
+ response: z.object({ saved: z.literal(true) }).strict(),
3048
+ error: HostApiErrorSchema,
3049
+ invalidatesSnapshot: true,
3050
+ }),
3051
+ listCommandMembers: defineContract({
3052
+ method: 'GET',
3053
+ path: '/api/commands/members/:channelId',
3054
+ params: z.object({ channelId: ChannelIdSchema }).strict(),
3055
+ request: NoRequestBodySchema,
3056
+ response: z
3057
+ .object({
3058
+ members: z.array(
3059
+ z
3060
+ .object({
3061
+ identityId: PlatformIdentityIdSchema,
3062
+ displayName: z.string(),
3063
+ platformUserId: z.string(),
3064
+ authorized: z.boolean(),
3065
+ })
3066
+ .strict(),
3067
+ ),
3068
+ })
3069
+ .strict(),
3070
+ error: HostApiErrorSchema,
3071
+ }),
3072
+ setCommandSettings: defineContract({
3073
+ method: 'PUT',
3074
+ path: '/api/commands/settings',
3075
+ params: EmptyParamsSchema,
3076
+ request: z.object({ unauthorizedFeedback: z.boolean() }).strict(),
3077
+ response: z.object({ saved: z.literal(true) }).strict(),
3078
+ error: HostApiErrorSchema,
3079
+ }),
3080
+ setCommandChannelSettings: defineContract({
3081
+ method: 'PUT',
3082
+ path: '/api/commands/channel-settings',
3083
+ params: EmptyParamsSchema,
3084
+ request: z.object({ channelId: ChannelIdSchema, bareCommands: z.boolean() }).strict(),
3085
+ response: z.object({ saved: z.literal(true) }).strict(),
3086
+ error: HostApiErrorSchema,
3087
+ invalidatesSnapshot: true,
3088
+ }),
3089
+ setCommandGrant: defineContract({
3090
+ method: 'PUT',
3091
+ path: '/api/commands/grants',
3092
+ params: EmptyParamsSchema,
3093
+ request: z
3094
+ .object({ channelId: ChannelIdSchema, identityId: PlatformIdentityIdSchema, enabled: z.boolean() })
3095
+ .strict(),
3096
+ response: z.object({ saved: z.literal(true) }).strict(),
3097
+ error: HostApiErrorSchema,
3098
+ invalidatesSnapshot: true,
3099
+ }),
3100
+ queryLogs: defineContract({
3101
+ method: 'GET',
3102
+ path: '/api/logs',
3103
+ params: z.object({ query: z.string().max(32_768).optional() }).strict(),
3104
+ request: NoRequestBodySchema,
3105
+ response: hostLogPageSchema,
3106
+ error: HostApiErrorSchema,
3107
+ }),
3108
+ getLog: defineContract({
3109
+ method: 'GET',
3110
+ path: '/api/logs/:id',
3111
+ params: z.object({ id: z.string().min(1).max(256) }).strict(),
3112
+ request: NoRequestBodySchema,
3113
+ response: z.object({ entry: hostLogEntrySchema }).strict(),
3114
+ error: HostApiErrorSchema,
3115
+ }),
3116
+ logSources: defineContract({
3117
+ method: 'GET',
3118
+ path: '/api/logs/sources',
3119
+ params: EmptyParamsSchema,
3120
+ request: NoRequestBodySchema,
3121
+ response: z.object({ sources: z.array(hostLogSourceSchema) }).strict(),
3122
+ error: HostApiErrorSchema,
3123
+ }),
3124
+ logStatus: defineContract({
3125
+ method: 'GET',
3126
+ path: '/api/logs/status',
3127
+ params: EmptyParamsSchema,
3128
+ request: NoRequestBodySchema,
3129
+ response: hostLogStatusSchema,
3130
+ error: HostApiErrorSchema,
3131
+ }),
3132
+ logSettings: defineContract({
3133
+ method: 'GET',
3134
+ path: '/api/logs/settings',
3135
+ params: EmptyParamsSchema,
3136
+ request: NoRequestBodySchema,
3137
+ response: hostLogSettingsSchema,
3138
+ error: HostApiErrorSchema,
3139
+ }),
3140
+ updateLogSettings: defineContract({
3141
+ method: 'PUT',
3142
+ path: '/api/logs/settings',
3143
+ params: EmptyParamsSchema,
3144
+ request: hostLogSettingsSchema,
3145
+ response: hostLogSettingsSchema,
3146
+ error: HostApiErrorSchema,
3147
+ }),
3148
+ startLogDebug: defineContract({
3149
+ method: 'POST',
3150
+ path: '/api/logs/debug',
3151
+ params: EmptyParamsSchema,
3152
+ request: hostLogDebugRequestSchema,
3153
+ response: z.object({ lease: hostLogDebugLeaseSchema }).strict(),
3154
+ error: HostApiErrorSchema,
3155
+ }),
3156
+ stopLogDebug: defineContract({
3157
+ method: 'DELETE',
3158
+ path: '/api/logs/debug/:id',
3159
+ params: z.object({ id: z.string().min(1).max(256) }).strict(),
3160
+ request: NoRequestBodySchema,
3161
+ response: z.object({ stopped: z.literal(true) }).strict(),
3162
+ error: HostApiErrorSchema,
3163
+ }),
3164
+ retryRuntimeCompatibility: defineContract({
3165
+ method: 'POST',
3166
+ path: '/api/runtime/compatibility/retry',
3167
+ params: EmptyParamsSchema,
3168
+ request: z
3169
+ .object({ objectKind: RuntimeCompatibilityDiagnosticSchema.shape.objectKind, objectId: z.string().min(1) })
3170
+ .strict(),
3171
+ response: z.object({ diagnostics: z.array(RuntimeCompatibilityDiagnosticSchema) }).strict(),
3172
+ error: HostApiErrorSchema,
3173
+ invalidatesSnapshot: true,
3174
+ }),
3175
+ snapshot: defineContract({
3176
+ method: 'GET',
3177
+ path: '/api/snapshot',
3178
+ params: EmptyParamsSchema,
3179
+ request: NoRequestBodySchema,
2235
3180
  response: HostSnapshotSchema,
2236
3181
  error: HostApiErrorSchema,
2237
3182
  }),
@@ -2244,11 +3189,20 @@ export const HostApiContracts = {
2244
3189
  .object({
2245
3190
  task: AuthoringTaskSummarySchema,
2246
3191
  attempts: z.array(AuthoringAttemptSummarySchema),
2247
- /** Secret fields of the latest candidate and which have a test value for this task's dynamic runs. */
2248
- testSecrets: z
3192
+ /**
3193
+ * Test configuration of this task's dynamic runs: fields of the latest candidate the user can type, which
3194
+ * credentials are set, the user's values and the values the agent provided.
3195
+ */
3196
+ testConfig: z
2249
3197
  .object({
2250
- fields: z.array(z.object({ key: z.string(), title: z.string() }).strict()),
3198
+ fields: z.array(
3199
+ z.object({ key: z.string(), title: z.string(), kind: z.enum(['secret', 'string', 'number']) }).strict(),
3200
+ ),
2251
3201
  configured: z.array(z.string()),
3202
+ values: z.record(z.string(), z.union([z.string(), z.number()])),
3203
+ agentValues: z.record(z.string(), JsonValueSchema),
3204
+ /** Secret fields bound to a named credential, by the user or else by the agent. */
3205
+ boundCredentials: BoundCredentialsSchema.optional(),
2252
3206
  })
2253
3207
  .strict()
2254
3208
  .optional(),
@@ -2298,12 +3252,26 @@ export const HostApiContracts = {
2298
3252
  response: AuthoringTaskSummarySchema,
2299
3253
  error: HostApiErrorSchema,
2300
3254
  }),
2301
- setAuthoringTestSecrets: defineContract({
3255
+ setAuthoringTestConfig: defineContract({
2302
3256
  method: 'PUT',
2303
3257
  path: '/api/authoring/tasks/:taskId/test-secrets',
2304
3258
  params: authoringTaskParam,
2305
- request: z.object({ secrets: z.record(z.string(), z.string().max(8192)) }).strict(),
2306
- response: z.object({ configured: z.array(z.string()) }).strict(),
3259
+ request: z
3260
+ .object({
3261
+ secrets: z.record(z.string(), z.string().max(8192)),
3262
+ /** Text and number values; an empty string goes back to the agent's value or the default. */
3263
+ values: z.record(z.string(), z.union([z.string().max(8192), z.number()])).optional(),
3264
+ /** Secret fields to bind to named credentials instead of a typed value; `null` leaves the field unset. */
3265
+ credentialBindings: CredentialBindingsRequestSchema.optional(),
3266
+ })
3267
+ .strict(),
3268
+ response: z
3269
+ .object({
3270
+ configured: z.array(z.string()),
3271
+ values: z.record(z.string(), z.union([z.string(), z.number()])),
3272
+ boundCredentials: BoundCredentialsSchema.optional(),
3273
+ })
3274
+ .strict(),
2307
3275
  error: HostApiErrorSchema,
2308
3276
  }),
2309
3277
  deleteAuthoringTask: defineContract({
@@ -2501,6 +3469,8 @@ export const HostApiContracts = {
2501
3469
  /** Messages from another local agent's account: `observe` keeps them as context unless they @ this agent. */
2502
3470
  localAgentMessages: z.enum(['observe', 'trigger']).optional(),
2503
3471
  activityTriggerOverrides: ActivityTriggerOverridesSchema.optional(),
3472
+ /** Omitted keeps the binding's current timing; `{}` resets every field to its default. */
3473
+ responseTiming: ResponseTimingSettingsSchema.optional(),
2504
3474
  })
2505
3475
  .strict(),
2506
3476
  response: z
@@ -2508,9 +3478,11 @@ export const HostApiContracts = {
2508
3478
  channelId: ChannelIdSchema,
2509
3479
  agentId: AgentIdSchema,
2510
3480
  triggerPolicy: TriggerPolicySchema,
3481
+ paused: z.boolean().default(false),
2511
3482
  processingFeedback: z.enum(['auto', 'off']).default('auto'),
2512
3483
  localAgentMessages: z.enum(['observe', 'trigger']).optional(),
2513
3484
  activityTriggerOverrides: ActivityTriggerOverridesSchema.default({}),
3485
+ responseTiming: ResponseTimingSettingsSchema.optional(),
2514
3486
  boundAt: z.number().int().safe().nonnegative(),
2515
3487
  })
2516
3488
  .strict(),
@@ -2534,6 +3506,23 @@ export const HostApiContracts = {
2534
3506
  response: WorkTreeOrderSchema,
2535
3507
  error: HostApiErrorSchema,
2536
3508
  }),
3509
+ getChannelListView: defineContract({
3510
+ method: 'GET',
3511
+ path: '/api/channel-list-view',
3512
+ params: EmptyParamsSchema,
3513
+ request: NoRequestBodySchema,
3514
+ response: ChannelListViewSchema,
3515
+ error: HostApiErrorSchema,
3516
+ }),
3517
+ updateChannelListView: defineContract({
3518
+ invalidatesSnapshot: true,
3519
+ method: 'PUT',
3520
+ path: '/api/channel-list-view',
3521
+ params: EmptyParamsSchema,
3522
+ request: ChannelListViewSchema,
3523
+ response: ChannelListViewSchema,
3524
+ error: HostApiErrorSchema,
3525
+ }),
2537
3526
  listChannelMessages: defineContract({
2538
3527
  method: 'GET',
2539
3528
  path: '/api/channels/:channelId/messages',
@@ -2569,12 +3558,44 @@ export const HostApiContracts = {
2569
3558
  .strict(),
2570
3559
  error: HostApiErrorSchema,
2571
3560
  }),
3561
+ uploadChannelAsset: defineContract({
3562
+ method: 'POST',
3563
+ path: '/api/channels/:channelId/assets',
3564
+ params: channelParam,
3565
+ request: BinaryUploadRequestSchema,
3566
+ encodeRequest: (input) => ({
3567
+ body: input.bytes,
3568
+ headers: {
3569
+ 'content-type': 'application/octet-stream',
3570
+ 'x-file-name': encodeURIComponent(input.fileName ?? '附件'),
3571
+ },
3572
+ }),
3573
+ response: z
3574
+ .object({
3575
+ assetId: AssetIdSchema,
3576
+ mediaType: z.string().min(1),
3577
+ byteSize: z.number().int().nonnegative(),
3578
+ fileName: z.string().min(1).max(255),
3579
+ partType: z.enum(['image', 'file']),
3580
+ })
3581
+ .strict(),
3582
+ error: HostApiErrorSchema,
3583
+ }),
3584
+ deleteChannelAsset: defineContract({
3585
+ method: 'DELETE',
3586
+ path: '/api/channels/:channelId/assets/:assetId',
3587
+ params: z.object({ channelId: ChannelIdSchema, assetId: AssetIdSchema }).strict(),
3588
+ request: NoRequestBodySchema,
3589
+ response: z.object({ assetId: AssetIdSchema, revoked: z.literal(true) }).strict(),
3590
+ error: HostApiErrorSchema,
3591
+ }),
2572
3592
  renameChannel: defineContract({
2573
3593
  invalidatesSnapshot: true,
2574
3594
  method: 'POST',
2575
3595
  path: '/api/channels/:channelId/display-name',
2576
3596
  params: channelParam,
2577
- request: z.object({ displayName: z.string().trim().min(1).max(120) }).strict(),
3597
+ /** Empty selects the known platform name for an external channel. */
3598
+ request: z.object({ displayName: z.string().trim().max(120) }).strict(),
2578
3599
  response: z.object({ channelId: ChannelIdSchema, displayName: z.string().trim().min(1).max(120) }).strict(),
2579
3600
  error: HostApiErrorSchema,
2580
3601
  }),
@@ -2616,6 +3637,57 @@ export const HostApiContracts = {
2616
3637
  response: ChannelRuntimeContextSchema,
2617
3638
  error: HostApiErrorSchema,
2618
3639
  }),
3640
+ listSubConversations: defineContract({
3641
+ method: 'GET',
3642
+ path: '/api/sub-conversations/channels/:channelId',
3643
+ params: channelParam,
3644
+ request: NoRequestBodySchema,
3645
+ response: z.object({ items: z.array(SubConversationSchema) }).strict(),
3646
+ error: HostApiErrorSchema,
3647
+ }),
3648
+ getSubConversationRuntime: defineContract({
3649
+ method: 'GET',
3650
+ path: '/api/sub-conversations/:conversationId/runtime',
3651
+ params: subConversationParam,
3652
+ request: NoRequestBodySchema,
3653
+ // Read from memory while it runs and from its stored log after it ended.
3654
+ response: z.object({ conversation: SubConversationSchema, runtime: ChannelRuntimeProjectionSchema }).strict(),
3655
+ error: HostApiErrorSchema,
3656
+ }),
3657
+ closeSubConversation: defineContract({
3658
+ invalidatesSnapshot: true,
3659
+ method: 'POST',
3660
+ path: '/api/sub-conversations/:conversationId/close',
3661
+ params: subConversationParam,
3662
+ request: z.object({}).strict(),
3663
+ response: SubConversationSchema,
3664
+ error: HostApiErrorSchema,
3665
+ }),
3666
+ deleteSubConversation: defineContract({
3667
+ invalidatesSnapshot: true,
3668
+ method: 'DELETE',
3669
+ path: '/api/sub-conversations/:conversationId',
3670
+ params: subConversationParam,
3671
+ request: NoRequestBodySchema,
3672
+ response: z.object({ deleted: z.literal(true) }).strict(),
3673
+ error: HostApiErrorSchema,
3674
+ }),
3675
+ getSubConversationSettings: defineContract({
3676
+ method: 'GET',
3677
+ path: '/api/settings/sub-conversations',
3678
+ params: EmptyParamsSchema,
3679
+ request: NoRequestBodySchema,
3680
+ response: SubConversationSettingsSchema,
3681
+ error: HostApiErrorSchema,
3682
+ }),
3683
+ updateSubConversationSettings: defineContract({
3684
+ method: 'PUT',
3685
+ path: '/api/settings/sub-conversations',
3686
+ params: EmptyParamsSchema,
3687
+ request: SubConversationSettingsSchema,
3688
+ response: SubConversationSettingsSchema,
3689
+ error: HostApiErrorSchema,
3690
+ }),
2619
3691
  getChannelRuntimeInput: defineContract({
2620
3692
  method: 'GET',
2621
3693
  path: '/api/channels/:channelId/runtime/inputs/:messageId',
@@ -2699,6 +3771,57 @@ export const HostApiContracts = {
2699
3771
  response: MessagePacingSettingsSchema,
2700
3772
  error: HostApiErrorSchema,
2701
3773
  }),
3774
+ getCompactionSettings: defineContract({
3775
+ method: 'GET',
3776
+ path: '/api/settings/compaction',
3777
+ params: EmptyParamsSchema,
3778
+ request: NoRequestBodySchema,
3779
+ response: CompactionSettingsSchema,
3780
+ error: HostApiErrorSchema,
3781
+ }),
3782
+ updateCompactionSettings: defineContract({
3783
+ invalidatesSnapshot: true,
3784
+ method: 'PUT',
3785
+ path: '/api/settings/compaction',
3786
+ params: EmptyParamsSchema,
3787
+ request: CompactionSettingsSchema,
3788
+ response: CompactionSettingsSchema,
3789
+ error: HostApiErrorSchema,
3790
+ }),
3791
+ getModelFallbackSettings: defineContract({
3792
+ method: 'GET',
3793
+ path: '/api/settings/model-fallback',
3794
+ params: EmptyParamsSchema,
3795
+ request: NoRequestBodySchema,
3796
+ response: ModelFallbackSettingsSchema,
3797
+ error: HostApiErrorSchema,
3798
+ }),
3799
+ updateModelFallbackSettings: defineContract({
3800
+ method: 'PUT',
3801
+ path: '/api/settings/model-fallback',
3802
+ params: EmptyParamsSchema,
3803
+ request: ModelFallbackSettingsSchema,
3804
+ response: ModelFallbackSettingsSchema,
3805
+ error: HostApiErrorSchema,
3806
+ }),
3807
+ getUpgradeBackupSettings: defineContract({
3808
+ method: 'GET',
3809
+ path: '/api/settings/upgrade-backup',
3810
+ params: EmptyParamsSchema,
3811
+ request: NoRequestBodySchema,
3812
+ response: UpgradeBackupSettingsSchema,
3813
+ error: HostApiErrorSchema,
3814
+ }),
3815
+ updateUpgradeBackupSettings: defineContract({
3816
+ method: 'PUT',
3817
+ path: '/api/settings/upgrade-backup',
3818
+ params: EmptyParamsSchema,
3819
+ request: z
3820
+ .object({ mode: UpgradeBackupModeSchema, directory: z.string().trim().min(1).max(1024).optional() })
3821
+ .strict(),
3822
+ response: UpgradeBackupSettingsSchema,
3823
+ error: HostApiErrorSchema,
3824
+ }),
2702
3825
  getRetrievalStatus: defineContract({
2703
3826
  method: 'GET',
2704
3827
  path: '/api/settings/retrieval',
@@ -2749,6 +3872,154 @@ export const HostApiContracts = {
2749
3872
  response: CodeRunAvailabilitySchema,
2750
3873
  error: HostApiErrorSchema,
2751
3874
  }),
3875
+ downloadGithubCli: defineContract({
3876
+ invalidatesSnapshot: true,
3877
+ method: 'POST',
3878
+ path: '/api/runtimes/github-cli/download',
3879
+ params: EmptyParamsSchema,
3880
+ request: NoRequestBodySchema,
3881
+ response: GithubCliAvailabilitySchema,
3882
+ error: HostApiErrorSchema,
3883
+ }),
3884
+ removeGithubCli: defineContract({
3885
+ invalidatesSnapshot: true,
3886
+ method: 'DELETE',
3887
+ path: '/api/runtimes/github-cli',
3888
+ params: EmptyParamsSchema,
3889
+ request: NoRequestBodySchema,
3890
+ response: GithubCliAvailabilitySchema,
3891
+ error: HostApiErrorSchema,
3892
+ }),
3893
+ downloadVerificationBrowser: defineContract({
3894
+ invalidatesSnapshot: true,
3895
+ method: 'POST',
3896
+ path: '/api/runtimes/verification-browser/download',
3897
+ params: EmptyParamsSchema,
3898
+ request: NoRequestBodySchema,
3899
+ response: VerificationBrowserAvailabilitySchema,
3900
+ error: HostApiErrorSchema,
3901
+ }),
3902
+ removeVerificationBrowser: defineContract({
3903
+ invalidatesSnapshot: true,
3904
+ method: 'DELETE',
3905
+ path: '/api/runtimes/verification-browser',
3906
+ params: EmptyParamsSchema,
3907
+ request: NoRequestBodySchema,
3908
+ response: VerificationBrowserAvailabilitySchema,
3909
+ error: HostApiErrorSchema,
3910
+ }),
3911
+ getLinkedAccounts: defineContract({
3912
+ method: 'GET',
3913
+ path: '/api/settings/linked-accounts',
3914
+ params: EmptyParamsSchema,
3915
+ request: NoRequestBodySchema,
3916
+ response: LinkedAccountsViewSchema,
3917
+ error: HostApiErrorSchema,
3918
+ }),
3919
+ addLinkedAccount: defineContract({
3920
+ invalidatesSnapshot: true,
3921
+ method: 'POST',
3922
+ path: '/api/settings/linked-accounts',
3923
+ params: EmptyParamsSchema,
3924
+ request: AddLinkedAccountRequestSchema,
3925
+ response: LinkedAccountsViewSchema,
3926
+ error: HostApiErrorSchema,
3927
+ }),
3928
+ replaceLinkedAccountToken: defineContract({
3929
+ invalidatesSnapshot: true,
3930
+ method: 'PUT',
3931
+ path: '/api/settings/linked-accounts/:accountId/token',
3932
+ params: linkedAccountParam,
3933
+ request: ReplaceLinkedAccountTokenRequestSchema,
3934
+ response: LinkedAccountsViewSchema,
3935
+ error: HostApiErrorSchema,
3936
+ }),
3937
+ removeLinkedAccount: defineContract({
3938
+ invalidatesSnapshot: true,
3939
+ method: 'POST',
3940
+ path: '/api/settings/linked-accounts/:accountId/remove',
3941
+ params: linkedAccountParam,
3942
+ request: RemoveLinkedAccountRequestSchema,
3943
+ response: RemoveLinkedAccountResultSchema,
3944
+ error: HostApiErrorSchema,
3945
+ }),
3946
+ getLinkedAccountUses: defineContract({
3947
+ method: 'GET',
3948
+ path: '/api/settings/linked-accounts/:accountId/uses',
3949
+ params: linkedAccountParam,
3950
+ request: NoRequestBodySchema,
3951
+ response: LinkedAccountUsesViewSchema,
3952
+ error: HostApiErrorSchema,
3953
+ }),
3954
+ getCredentials: defineContract({
3955
+ method: 'GET',
3956
+ path: '/api/settings/credentials',
3957
+ params: EmptyParamsSchema,
3958
+ request: NoRequestBodySchema,
3959
+ response: CredentialsViewSchema,
3960
+ error: HostApiErrorSchema,
3961
+ }),
3962
+ createCredential: defineContract({
3963
+ invalidatesSnapshot: true,
3964
+ method: 'POST',
3965
+ path: '/api/settings/credentials',
3966
+ params: EmptyParamsSchema,
3967
+ request: CreateCredentialRequestSchema,
3968
+ response: CredentialsViewSchema,
3969
+ error: HostApiErrorSchema,
3970
+ }),
3971
+ updateCredential: defineContract({
3972
+ invalidatesSnapshot: true,
3973
+ method: 'PATCH',
3974
+ path: '/api/settings/credentials/:credentialId',
3975
+ params: credentialParam,
3976
+ request: UpdateCredentialRequestSchema,
3977
+ response: CredentialsViewSchema,
3978
+ error: HostApiErrorSchema,
3979
+ }),
3980
+ replaceCredentialValue: defineContract({
3981
+ invalidatesSnapshot: true,
3982
+ method: 'PUT',
3983
+ path: '/api/settings/credentials/:credentialId/value',
3984
+ params: credentialParam,
3985
+ request: ReplaceCredentialValueRequestSchema,
3986
+ response: CredentialsViewSchema,
3987
+ error: HostApiErrorSchema,
3988
+ }),
3989
+ removeCredential: defineContract({
3990
+ invalidatesSnapshot: true,
3991
+ method: 'POST',
3992
+ path: '/api/settings/credentials/:credentialId/remove',
3993
+ params: credentialParam,
3994
+ request: RemoveCredentialRequestSchema,
3995
+ response: RemoveCredentialResultSchema,
3996
+ error: HostApiErrorSchema,
3997
+ }),
3998
+ getCredentialUses: defineContract({
3999
+ method: 'GET',
4000
+ path: '/api/settings/credentials/:credentialId/uses',
4001
+ params: credentialParam,
4002
+ request: NoRequestBodySchema,
4003
+ response: CredentialUsesViewSchema,
4004
+ error: HostApiErrorSchema,
4005
+ }),
4006
+ dismissCredentialRequest: defineContract({
4007
+ method: 'DELETE',
4008
+ path: '/api/settings/credentials/requests/:requestId',
4009
+ params: z.object({ requestId: NonEmptyStringSchema.max(64) }).strict(),
4010
+ request: NoRequestBodySchema,
4011
+ response: CredentialsViewSchema,
4012
+ error: HostApiErrorSchema,
4013
+ }),
4014
+ setModelProviderAccess: defineContract({
4015
+ invalidatesSnapshot: true,
4016
+ method: 'PUT',
4017
+ path: '/api/settings/credentials/model-providers/:provider',
4018
+ params: z.object({ provider: NonEmptyStringSchema.max(128) }).strict(),
4019
+ request: SetModelProviderAccessRequestSchema,
4020
+ response: CredentialsViewSchema,
4021
+ error: HostApiErrorSchema,
4022
+ }),
2752
4023
  getChannelMemberNotes: defineContract({
2753
4024
  method: 'GET',
2754
4025
  path: '/api/channels/:channelId/member-notes',
@@ -2899,7 +4170,13 @@ export const HostApiContracts = {
2899
4170
  method: 'POST',
2900
4171
  path: '/api/connections/:connectionId/configuration',
2901
4172
  params: connectionParam,
2902
- request: z.object({ configuration: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])) }).strict(),
4173
+ request: z
4174
+ .object({
4175
+ configuration: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])),
4176
+ /** Omitted keys keep their value; null explicitly clears an optional credential. */
4177
+ credentials: z.record(z.string().min(1), z.string().min(1).max(16_384).nullable()).optional(),
4178
+ })
4179
+ .strict(),
2903
4180
  response: z
2904
4181
  .object({
2905
4182
  connectionId: ConnectionIdSchema,
@@ -3016,61 +4293,194 @@ export const HostApiContracts = {
3016
4293
  request: z.object({ targetKey: NonEmptyStringSchema }).strict(),
3017
4294
  response: z.object({ disabled: z.literal(true) }).strict(),
3018
4295
  error: HostApiErrorSchema,
3019
- }),
3020
- removeDshPluginPackage: defineContract({
4296
+ }),
4297
+ removeDshPluginPackage: defineContract({
4298
+ invalidatesSnapshot: true,
4299
+ method: 'DELETE',
4300
+ path: '/api/dsh/plugin-installs/:packageId',
4301
+ params: dshPluginPackageParam,
4302
+ request: NoRequestBodySchema,
4303
+ response: z.object({ removed: z.literal(true) }).strict(),
4304
+ error: HostApiErrorSchema,
4305
+ }),
4306
+ inspectExtensionImport: defineContract({
4307
+ timeoutMs: 300_000,
4308
+ method: 'POST',
4309
+ path: '/api/extensions/imports/inspect',
4310
+ params: EmptyParamsSchema,
4311
+ request: BinaryUploadRequestSchema,
4312
+ encodeRequest: encodeBinaryUpload,
4313
+ response: ExtensionImportInspectionSchema,
4314
+ error: HostApiErrorSchema,
4315
+ }),
4316
+ /**
4317
+ * Management-edge endpoints: they exist only when the Server is reached through its management edge (a management
4318
+ * key is set); clients tell that from the edge's CSRF cookie.
4319
+ */
4320
+ listManagementDevices: defineContract({
4321
+ method: 'GET',
4322
+ path: '/api/management/devices',
4323
+ params: EmptyParamsSchema,
4324
+ request: NoRequestBodySchema,
4325
+ response: z.object({ devices: z.array(ManagementDeviceViewSchema) }).strict(),
4326
+ error: HostApiErrorSchema,
4327
+ }),
4328
+ revokeManagementDevice: defineContract({
4329
+ method: 'DELETE',
4330
+ path: '/api/management/devices/:deviceId',
4331
+ params: z.object({ deviceId: ManagementDeviceIdSchema }).strict(),
4332
+ request: NoRequestBodySchema,
4333
+ response: z.object({ revoked: z.boolean() }).strict(),
4334
+ error: HostApiErrorSchema,
4335
+ }),
4336
+ managementLogout: defineContract({
4337
+ method: 'DELETE',
4338
+ path: '/api/management/session',
4339
+ params: EmptyParamsSchema,
4340
+ request: NoRequestBodySchema,
4341
+ response: z.object({ authenticated: z.literal(false) }).strict(),
4342
+ error: HostApiErrorSchema,
4343
+ }),
4344
+ getCommunityStatus: defineContract({
4345
+ method: 'GET',
4346
+ path: '/api/community/status',
4347
+ params: EmptyParamsSchema,
4348
+ request: NoRequestBodySchema,
4349
+ response: CommunityStatusSchema,
4350
+ error: HostApiErrorSchema,
4351
+ }),
4352
+ getCommunityFeedbackSettings: defineContract({
4353
+ method: 'GET',
4354
+ path: '/api/community/feedback/settings',
4355
+ params: EmptyParamsSchema,
4356
+ request: NoRequestBodySchema,
4357
+ response: CommunityFeedbackSettingsSchema,
4358
+ error: HostApiErrorSchema,
4359
+ }),
4360
+ updateCommunityFeedbackSettings: defineContract({
4361
+ method: 'PUT',
4362
+ path: '/api/community/feedback/settings',
4363
+ params: EmptyParamsSchema,
4364
+ request: CommunityFeedbackSettingsUpdateSchema,
4365
+ response: CommunityFeedbackSettingsSchema,
4366
+ error: HostApiErrorSchema,
4367
+ invalidatesSnapshot: true,
4368
+ }),
4369
+ listCommunityFeedback: defineContract({
4370
+ timeoutMs: 60_000,
4371
+ method: 'GET',
4372
+ path: '/api/community/feedback',
4373
+ params: z.object({ refresh: z.literal('1').optional() }).strict(),
4374
+ request: NoRequestBodySchema,
4375
+ response: CommunityFeedbackLocalListSchema,
4376
+ error: HostApiErrorSchema,
4377
+ }),
4378
+ getCommunityFeedback: defineContract({
4379
+ timeoutMs: 60_000,
4380
+ method: 'GET',
4381
+ path: '/api/community/feedback/items/:ref',
4382
+ params: z.object({ ref: CommunityFeedbackRefSchema }).strict(),
4383
+ request: NoRequestBodySchema,
4384
+ response: CommunityFeedbackSchema,
4385
+ error: HostApiErrorSchema,
4386
+ }),
4387
+ createCommunityFeedbackDraft: defineContract({
4388
+ method: 'POST',
4389
+ path: '/api/community/feedback/drafts',
4390
+ params: EmptyParamsSchema,
4391
+ request: CommunityFeedbackDraftInputSchema,
4392
+ response: CommunityFeedbackDraftSchema,
4393
+ error: HostApiErrorSchema,
4394
+ invalidatesSnapshot: true,
4395
+ }),
4396
+ updateCommunityFeedbackDraft: defineContract({
4397
+ method: 'PUT',
4398
+ path: '/api/community/feedback/drafts/:draftId',
4399
+ params: z.object({ draftId: CommunityFeedbackDraftIdSchema }).strict(),
4400
+ request: CommunityFeedbackDraftUpdateSchema,
4401
+ response: CommunityFeedbackDraftSchema,
4402
+ error: HostApiErrorSchema,
4403
+ invalidatesSnapshot: true,
4404
+ }),
4405
+ sendCommunityFeedbackDraft: defineContract({
4406
+ timeoutMs: 60_000,
4407
+ method: 'POST',
4408
+ path: '/api/community/feedback/drafts/:draftId/send',
4409
+ params: z.object({ draftId: CommunityFeedbackDraftIdSchema }).strict(),
4410
+ request: z.object({ consent: z.boolean().default(false) }).strict(),
4411
+ response: CommunityFeedbackDraftSchema,
4412
+ error: HostApiErrorSchema,
3021
4413
  invalidatesSnapshot: true,
4414
+ }),
4415
+ discardCommunityFeedbackDraft: defineContract({
3022
4416
  method: 'DELETE',
3023
- path: '/api/dsh/plugin-installs/:packageId',
3024
- params: dshPluginPackageParam,
4417
+ path: '/api/community/feedback/drafts/:draftId',
4418
+ params: z.object({ draftId: CommunityFeedbackDraftIdSchema }).strict(),
3025
4419
  request: NoRequestBodySchema,
3026
- response: z.object({ removed: z.literal(true) }).strict(),
4420
+ response: CommunityFeedbackDraftSchema,
3027
4421
  error: HostApiErrorSchema,
4422
+ invalidatesSnapshot: true,
3028
4423
  }),
3029
- inspectExtensionImport: defineContract({
3030
- timeoutMs: 300_000,
3031
- method: 'POST',
3032
- path: '/api/extensions/imports/inspect',
3033
- params: EmptyParamsSchema,
3034
- request: BinaryUploadRequestSchema,
3035
- encodeRequest: encodeBinaryUpload,
3036
- response: ExtensionImportInspectionSchema,
4424
+ previewCommunityFeedbackPayload: defineContract({
4425
+ method: 'GET',
4426
+ path: '/api/community/feedback/drafts/:draftId/preview',
4427
+ params: z.object({ draftId: CommunityFeedbackDraftIdSchema }).strict(),
4428
+ request: NoRequestBodySchema,
4429
+ response: CommunityFeedbackPayloadSchema,
3037
4430
  error: HostApiErrorSchema,
3038
4431
  }),
3039
- /**
3040
- * Management-edge endpoints: they exist only when the Server is reached through its management edge (a management
3041
- * key is set); clients tell that from the edge's CSRF cookie.
3042
- */
3043
- listManagementDevices: defineContract({
4432
+ getLastSentCommunityFeedbackPayload: defineContract({
3044
4433
  method: 'GET',
3045
- path: '/api/management/devices',
4434
+ path: '/api/community/feedback/last-sent',
3046
4435
  params: EmptyParamsSchema,
3047
4436
  request: NoRequestBodySchema,
3048
- response: z.object({ devices: z.array(ManagementDeviceViewSchema) }).strict(),
4437
+ response: CommunityFeedbackLastPayloadSchema,
3049
4438
  error: HostApiErrorSchema,
3050
4439
  }),
3051
- revokeManagementDevice: defineContract({
3052
- method: 'DELETE',
3053
- path: '/api/management/devices/:deviceId',
3054
- params: z.object({ deviceId: ManagementDeviceIdSchema }).strict(),
3055
- request: NoRequestBodySchema,
3056
- response: z.object({ revoked: z.boolean() }).strict(),
4440
+ replyCommunityFeedback: defineContract({
4441
+ method: 'POST',
4442
+ path: '/api/community/feedback/items/:ref/messages',
4443
+ params: z.object({ ref: CommunityFeedbackRefSchema }).strict(),
4444
+ request: z.object({ body: z.string().trim().min(1).max(4000) }).strict(),
4445
+ response: CommunityFeedbackSchema,
3057
4446
  error: HostApiErrorSchema,
4447
+ invalidatesSnapshot: true,
3058
4448
  }),
3059
- managementLogout: defineContract({
3060
- method: 'DELETE',
3061
- path: '/api/management/session',
3062
- params: EmptyParamsSchema,
3063
- request: NoRequestBodySchema,
3064
- response: z.object({ authenticated: z.literal(false) }).strict(),
4449
+ withdrawCommunityFeedback: defineContract({
4450
+ method: 'POST',
4451
+ path: '/api/community/feedback/items/:ref/withdraw',
4452
+ params: z.object({ ref: CommunityFeedbackRefSchema }).strict(),
4453
+ request: CommunityFeedbackWithdrawSchema,
4454
+ response: CommunityFeedbackSchema,
3065
4455
  error: HostApiErrorSchema,
4456
+ invalidatesSnapshot: true,
3066
4457
  }),
3067
- getCommunityStatus: defineContract({
3068
- method: 'GET',
3069
- path: '/api/community/status',
3070
- params: EmptyParamsSchema,
3071
- request: NoRequestBodySchema,
3072
- response: CommunityStatusSchema,
4458
+ reopenCommunityFeedback: defineContract({
4459
+ method: 'POST',
4460
+ path: '/api/community/feedback/items/:ref/reopen',
4461
+ params: z.object({ ref: CommunityFeedbackRefSchema }).strict(),
4462
+ request: CommunityFeedbackReopenSchema,
4463
+ response: CommunityFeedbackSchema,
3073
4464
  error: HostApiErrorSchema,
4465
+ invalidatesSnapshot: true,
4466
+ }),
4467
+ markCommunityFeedbackAffected: defineContract({
4468
+ method: 'POST',
4469
+ path: '/api/community/feedback/items/:ref/affected',
4470
+ params: z.object({ ref: CommunityFeedbackRefSchema }).strict(),
4471
+ request: z.object({ affected: z.boolean().default(true), consent: z.boolean().default(false) }).strict(),
4472
+ response: CommunityFeedbackSchema,
4473
+ error: HostApiErrorSchema,
4474
+ invalidatesSnapshot: true,
4475
+ }),
4476
+ confirmCommunityFeedbackFixed: defineContract({
4477
+ method: 'POST',
4478
+ path: '/api/community/feedback/items/:ref/confirm-fixed',
4479
+ params: z.object({ ref: CommunityFeedbackRefSchema }).strict(),
4480
+ request: z.object({}).strict(),
4481
+ response: CommunityFeedbackSchema,
4482
+ error: HostApiErrorSchema,
4483
+ invalidatesSnapshot: true,
3074
4484
  }),
3075
4485
  startCommunityLogin: defineContract({
3076
4486
  method: 'POST',
@@ -3102,19 +4512,24 @@ export const HostApiContracts = {
3102
4512
  /** 排序方式,默认最近更新;游标只在同一种排序下有效。 */
3103
4513
  sort: CommunityExtensionSortSchema.optional(),
3104
4514
  cursor: z.string().max(200).optional(),
4515
+ /** 跳过本机缓存,重新向社区读取。 */
4516
+ refresh: z.enum(['1']).optional(),
3105
4517
  })
3106
4518
  .strict(),
3107
4519
  request: NoRequestBodySchema,
3108
- response: z.object({ items: z.array(CommunityExtensionSummarySchema), nextCursor: z.string().nullable() }).strict(),
4520
+ response: z
4521
+ .object({ items: z.array(CommunityExtensionSummarySchema), nextCursor: z.string().nullable() })
4522
+ .extend(CommunityFreshnessSchema.shape)
4523
+ .strict(),
3109
4524
  error: HostApiErrorSchema,
3110
4525
  }),
3111
4526
  getCommunityExtension: defineContract({
3112
4527
  timeoutMs: 30_000,
3113
4528
  method: 'GET',
3114
4529
  path: '/api/community/extensions/:extensionId',
3115
- params: z.object({ extensionId: ExtensionIdSchema }).strict(),
4530
+ params: z.object({ extensionId: ExtensionIdSchema, refresh: z.enum(['1']).optional() }).strict(),
3116
4531
  request: NoRequestBodySchema,
3117
- response: CommunityExtensionDetailSchema,
4532
+ response: CommunityExtensionDetailSchema.extend(CommunityFreshnessSchema.shape),
3118
4533
  error: HostApiErrorSchema,
3119
4534
  }),
3120
4535
  /** 下载社区发布并按包摘要校验,结果与本地文件导入的检查相同,再经 `commitExtensionImport` 确认。 */
@@ -3151,13 +4566,13 @@ export const HostApiContracts = {
3151
4566
  .strict(),
3152
4567
  error: HostApiErrorSchema,
3153
4568
  }),
3154
- listCommunityInstalled: defineContract({
3155
- timeoutMs: 30_000,
4569
+ listCommunitySync: defineContract({
4570
+ timeoutMs: 60_000,
3156
4571
  method: 'GET',
3157
- path: '/api/community/installed',
4572
+ path: '/api/community/sync',
3158
4573
  params: z.object({ refresh: z.enum(['1']).optional() }).strict(),
3159
4574
  request: NoRequestBodySchema,
3160
- response: CommunityInstalledSchema,
4575
+ response: CommunitySyncSchema,
3161
4576
  error: HostApiErrorSchema,
3162
4577
  }),
3163
4578
  listCommunityMine: defineContract({
@@ -3222,6 +4637,7 @@ export const HostApiContracts = {
3222
4637
  response: z
3223
4638
  .object({
3224
4639
  releaseId: CommunityReleaseIdSchema,
4640
+ releaseNumber: z.number().int().positive(),
3225
4641
  reviewStatus: CommunityReviewStatusSchema,
3226
4642
  pageUrl: z.string().url(),
3227
4643
  reportUrl: z.string().url(),
@@ -3240,19 +4656,24 @@ export const HostApiContracts = {
3240
4656
  tag: z.string().trim().min(1).max(40).optional(),
3241
4657
  official: z.literal('1').optional(),
3242
4658
  cursor: z.string().min(1).max(500).optional(),
4659
+ /** 跳过本机缓存,重新向社区读取。 */
4660
+ refresh: z.enum(['1']).optional(),
3243
4661
  })
3244
4662
  .strict(),
3245
4663
  request: NoRequestBodySchema,
3246
- response: z.object({ items: z.array(CommunityPersonaSummarySchema), nextCursor: z.string().nullable() }).strict(),
4664
+ response: z
4665
+ .object({ items: z.array(CommunityPersonaSummarySchema), nextCursor: z.string().nullable() })
4666
+ .extend(CommunityFreshnessSchema.shape)
4667
+ .strict(),
3247
4668
  error: HostApiErrorSchema,
3248
4669
  }),
3249
4670
  getCommunityPersona: defineContract({
3250
4671
  timeoutMs: 30_000,
3251
4672
  method: 'GET',
3252
4673
  path: '/api/community/personas/:personaId',
3253
- params: z.object({ personaId: CommunityPersonaIdSchema }).strict(),
4674
+ params: z.object({ personaId: CommunityPersonaIdSchema, refresh: z.enum(['1']).optional() }).strict(),
3254
4675
  request: NoRequestBodySchema,
3255
- response: CommunityPersonaDetailSchema,
4676
+ response: CommunityPersonaDetailSchema.extend(CommunityFreshnessSchema.shape),
3256
4677
  error: HostApiErrorSchema,
3257
4678
  }),
3258
4679
  /**
@@ -3447,6 +4868,31 @@ export const HostApiContracts = {
3447
4868
  response: LlmProviderSettingsSchema,
3448
4869
  error: HostApiErrorSchema,
3449
4870
  }),
4871
+ llmSubscriptionStatus: defineContract({
4872
+ method: 'GET',
4873
+ path: '/api/llm/subscriptions/:provider',
4874
+ params: llmProviderParam,
4875
+ request: NoRequestBodySchema,
4876
+ response: SubscriptionStatusSchema,
4877
+ error: HostApiErrorSchema,
4878
+ }),
4879
+ llmSubscriptionAction: defineContract({
4880
+ invalidatesSnapshot: true,
4881
+ method: 'POST',
4882
+ path: '/api/llm/subscriptions/:provider',
4883
+ params: llmProviderParam,
4884
+ request: z.discriminatedUnion('action', [
4885
+ z.object({ action: z.literal('use-subscription'), expectedRevision: z.number().int().nonnegative() }).strict(),
4886
+ z.object({ action: z.enum(['login', 'cancel']) }).strict(),
4887
+ z.object({ action: z.literal('answer'), promptId: NonEmptyStringSchema, value: z.string().max(4096) }).strict(),
4888
+ z.object({ action: z.enum(['activate', 'remove']), accountId: NonEmptyStringSchema }).strict(),
4889
+ z
4890
+ .object({ action: z.literal('rename'), accountId: NonEmptyStringSchema, label: z.string().min(1).max(80) })
4891
+ .strict(),
4892
+ ]),
4893
+ response: z.object({ status: SubscriptionStatusSchema, revocationConfirmed: z.boolean().optional() }).strict(),
4894
+ error: HostApiErrorSchema,
4895
+ }),
3450
4896
  llmDiscoverModels: defineContract({
3451
4897
  method: 'POST',
3452
4898
  path: '/api/llm/discover-models',
@@ -3594,7 +5040,19 @@ export const HostApiContracts = {
3594
5040
  path: '/api/dynamic/:agentId/decline',
3595
5041
  params: agentParam,
3596
5042
  request: z
3597
- .object({ episodeId: EpisodeIdSchema, requestId: DynamicIdSchema, pluginRunId: DynamicIdSchema.optional() })
5043
+ .object({
5044
+ episodeId: EpisodeIdSchema,
5045
+ requestId: DynamicIdSchema,
5046
+ pluginRunId: DynamicIdSchema.optional(),
5047
+ /**
5048
+ * Why the run did not go ahead: the user declined it, or the page could not start one of its halves. A failed
5049
+ * half is settled as a failed attempt (its Host is retracted and the agent hears about it), not as a decline.
5050
+ */
5051
+ reason: z.enum(['rejected', 'host-half-failed', 'client-half-failed']).optional(),
5052
+ startedHere: z.boolean().optional(),
5053
+ message: z.string().max(4000).optional(),
5054
+ stack: z.string().max(16000).optional(),
5055
+ })
3598
5056
  .strict(),
3599
5057
  response: z.object({ accepted: z.boolean() }).strict(),
3600
5058
  error: HostApiErrorSchema,
@@ -3750,36 +5208,20 @@ export const HostApiContracts = {
3750
5208
  method: 'POST',
3751
5209
  path: '/api/extensions/save-from-dynamic',
3752
5210
  params: EmptyParamsSchema,
3753
- request: z.union([
3754
- z
3755
- .object({
3756
- taskId: AuthoringTaskIdSchema,
3757
- attemptId: AuthoringAttemptIdSchema,
3758
- displayName: z.string().trim().min(1).max(80),
3759
- slug: z
3760
- .string()
3761
- .trim()
3762
- .regex(/^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/u),
3763
- description: z.string().max(500).default(''),
3764
- targetExtensionId: ExtensionIdSchema.optional(),
3765
- })
3766
- .strict(),
3767
- z
3768
- .object({
3769
- agentId: AgentIdSchema,
3770
- episodeId: EpisodeIdSchema,
3771
- pluginId: DynamicIdSchema,
3772
- packageId: DynamicIdSchema,
3773
- displayName: z.string().trim().min(1).max(80),
3774
- slug: z
3775
- .string()
3776
- .trim()
3777
- .regex(/^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/u),
3778
- description: z.string().max(500).default(''),
3779
- targetExtensionId: ExtensionIdSchema.optional(),
3780
- })
3781
- .strict(),
3782
- ]),
5211
+ request: z
5212
+ .object({
5213
+ taskId: AuthoringTaskIdSchema,
5214
+ /** The candidate the user saw; saving refuses when a newer one appeared since. */
5215
+ attemptId: AuthoringAttemptIdSchema,
5216
+ displayName: z.string().trim().min(1).max(80),
5217
+ slug: z
5218
+ .string()
5219
+ .trim()
5220
+ .regex(/^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/u),
5221
+ description: z.string().max(500).default(''),
5222
+ targetExtensionId: ExtensionIdSchema.optional(),
5223
+ })
5224
+ .strict(),
3783
5225
  response: z
3784
5226
  .object({
3785
5227
  extensionId: ExtensionIdSchema,
@@ -3860,6 +5302,7 @@ export const HostApiContracts = {
3860
5302
  extensionRevisionId: ExtensionRevisionIdSchema,
3861
5303
  config: JsonValueSchema,
3862
5304
  configuredSecrets: z.array(z.string()).optional(),
5305
+ boundCredentials: BoundCredentialsSchema.optional(),
3863
5306
  activatedAt: z.number().int().safe().nonnegative(),
3864
5307
  })
3865
5308
  .strict()
@@ -3880,6 +5323,16 @@ export const HostApiContracts = {
3880
5323
  response: z.object({ disabled: z.literal(true), pending: ExtensionActivationTransitionSchema.optional() }).strict(),
3881
5324
  error: HostApiErrorSchema,
3882
5325
  }),
5326
+ putAgentOutboundOrder: defineContract({
5327
+ invalidatesSnapshot: true,
5328
+ method: 'PUT',
5329
+ path: '/api/agents/:agentId/outbound-order',
5330
+ params: agentParam,
5331
+ /** Every enabled extension that processes the agent's messages before sending, in the new order. */
5332
+ request: z.object({ extensionIds: z.array(ExtensionIdSchema).max(64) }).strict(),
5333
+ response: z.object({ extensionIds: z.array(ExtensionIdSchema) }).strict(),
5334
+ error: HostApiErrorSchema,
5335
+ }),
3883
5336
  updateExtensionActivationConfig: defineContract({
3884
5337
  invalidatesSnapshot: true,
3885
5338
  method: 'PUT',
@@ -3890,9 +5343,17 @@ export const HostApiContracts = {
3890
5343
  config: JsonValueSchema,
3891
5344
  /** Write-only credential drafts keyed by secret field; an absent or empty draft keeps the stored one. */
3892
5345
  secrets: z.record(z.string(), z.string().max(8192)).optional(),
5346
+ /** Secret fields to bind to named credentials instead of a typed value; a field takes one or the other. */
5347
+ credentialBindings: CredentialBindingsRequestSchema.optional(),
5348
+ })
5349
+ .strict(),
5350
+ response: z
5351
+ .object({
5352
+ config: JsonValueSchema,
5353
+ configuredSecrets: z.array(z.string()).optional(),
5354
+ boundCredentials: BoundCredentialsSchema.optional(),
3893
5355
  })
3894
5356
  .strict(),
3895
- response: z.object({ config: JsonValueSchema, configuredSecrets: z.array(z.string()).optional() }).strict(),
3896
5357
  error: HostApiErrorSchema,
3897
5358
  }),
3898
5359
  updateHostExtensionConfig: defineContract({
@@ -3906,9 +5367,37 @@ export const HostApiContracts = {
3906
5367
  config: JsonValueSchema,
3907
5368
  /** Write-only credential drafts keyed by secret field; an absent or empty draft keeps the stored one. */
3908
5369
  secrets: z.record(z.string(), z.string().max(8192)).optional(),
5370
+ /** Secret fields to bind to named credentials instead of a typed value; a field takes one or the other. */
5371
+ credentialBindings: CredentialBindingsRequestSchema.optional(),
3909
5372
  })
3910
5373
  .strict(),
3911
- response: z.object({ config: JsonValueSchema, configuredSecrets: z.array(z.string()).optional() }).strict(),
5374
+ response: z
5375
+ .object({
5376
+ config: JsonValueSchema,
5377
+ configuredSecrets: z.array(z.string()).optional(),
5378
+ boundCredentials: BoundCredentialsSchema.optional(),
5379
+ })
5380
+ .strict(),
5381
+ error: HostApiErrorSchema,
5382
+ }),
5383
+ /** Configuration history of one extension, newest first: the host layer and every agent's configuration. */
5384
+ getExtensionConfigVersions: defineContract({
5385
+ method: 'GET',
5386
+ path: '/api/extensions/:extensionId/config-versions',
5387
+ params: extensionParam,
5388
+ request: NoRequestBodySchema,
5389
+ response: z.object({ versions: z.array(ExtensionConfigVersionSchema) }).strict(),
5390
+ error: HostApiErrorSchema,
5391
+ }),
5392
+ /** Writes an earlier configuration again as a new version of the same layer (and agent). */
5393
+ revertExtensionConfig: defineContract({
5394
+ invalidatesSnapshot: true,
5395
+ timeoutMs: 300_000,
5396
+ method: 'POST',
5397
+ path: '/api/extensions/:extensionId/config-versions/:versionId/revert',
5398
+ params: extensionConfigVersionParam,
5399
+ request: z.object({ reason: z.string().trim().max(500).optional() }).strict(),
5400
+ response: z.object({ version: ExtensionConfigVersionSchema }).strict(),
3912
5401
  error: HostApiErrorSchema,
3913
5402
  }),
3914
5403
  installHostExtension: defineContract({
@@ -3924,6 +5413,8 @@ export const HostApiContracts = {
3924
5413
  permissionApproval: PermissionApprovalSchema.optional(),
3925
5414
  /** Approval of expanded agent-layer capabilities for the agents that move to this Revision. */
3926
5415
  agentPermissionApproval: PermissionApprovalSchema.optional(),
5416
+ /** Data copy to put back first, when the target Revision only reads an older data version. */
5417
+ restoreDataSnapshotId: z.string().min(1).max(80).optional(),
3927
5418
  })
3928
5419
  .strict(),
3929
5420
  response: z
@@ -4040,6 +5531,15 @@ export const HostApiContracts = {
4040
5531
  .strict(),
4041
5532
  error: HostApiErrorSchema,
4042
5533
  }),
5534
+ setChannelPaused: defineContract({
5535
+ method: 'POST',
5536
+ path: '/api/channels/:channelId/pause',
5537
+ params: channelParam,
5538
+ request: z.object({ paused: z.boolean() }).strict(),
5539
+ response: z.object({ paused: z.boolean(), changed: z.boolean(), stopped: z.boolean() }).strict(),
5540
+ error: HostApiErrorSchema,
5541
+ invalidatesSnapshot: true,
5542
+ }),
4043
5543
  resolveOutbound: defineContract({
4044
5544
  method: 'POST',
4045
5545
  path: '/api/outbound/:outboundId/resolve',
@@ -4114,6 +5614,196 @@ export const HostApiContracts = {
4114
5614
  response: z.object({ deleted: z.literal(true) }).strict(),
4115
5615
  error: HostApiErrorSchema,
4116
5616
  }),
5617
+ getExtensionLineage: defineContract({
5618
+ method: 'GET',
5619
+ path: '/api/extensions/:extensionId/lineage',
5620
+ params: extensionParam,
5621
+ request: NoRequestBodySchema,
5622
+ response: ExtensionLineageSchema,
5623
+ error: HostApiErrorSchema,
5624
+ }),
5625
+ branchExtension: defineContract({
5626
+ invalidatesSnapshot: true,
5627
+ timeoutMs: 300_000,
5628
+ method: 'POST',
5629
+ path: '/api/extensions/:extensionId/branch',
5630
+ params: extensionParam,
5631
+ request: z
5632
+ .object({
5633
+ revisionId: ExtensionRevisionIdSchema,
5634
+ name: z.string().trim().min(1).max(80),
5635
+ slug: z
5636
+ .string()
5637
+ .trim()
5638
+ .regex(/^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/u)
5639
+ .optional(),
5640
+ copyData: z.boolean(),
5641
+ })
5642
+ .strict(),
5643
+ response: z.object({ extensionId: ExtensionIdSchema, revisionId: ExtensionRevisionIdSchema }).strict(),
5644
+ error: HostApiErrorSchema,
5645
+ }),
5646
+ rollbackExtension: defineContract({
5647
+ invalidatesSnapshot: true,
5648
+ timeoutMs: 300_000,
5649
+ method: 'POST',
5650
+ path: '/api/extensions/:extensionId/revert',
5651
+ params: extensionParam,
5652
+ request: NoRequestBodySchema,
5653
+ response: z.object({ message: z.string() }).strict(),
5654
+ error: HostApiErrorSchema,
5655
+ }),
5656
+ getExtensionData: defineContract({
5657
+ method: 'GET',
5658
+ path: '/api/extensions/:extensionId/data',
5659
+ params: extensionParam,
5660
+ request: NoRequestBodySchema,
5661
+ response: ExtensionDataStateSchema,
5662
+ error: HostApiErrorSchema,
5663
+ }),
5664
+ previewExtensionDataMigration: defineContract({
5665
+ timeoutMs: 60_000,
5666
+ method: 'POST',
5667
+ path: '/api/extensions/:extensionId/data/preview',
5668
+ params: extensionParam,
5669
+ request: ExtensionDataMigrationInputSchema,
5670
+ response: ExtensionDataPreviewSchema,
5671
+ error: HostApiErrorSchema,
5672
+ }),
5673
+ migrateExtensionData: defineContract({
5674
+ invalidatesSnapshot: true,
5675
+ timeoutMs: 300_000,
5676
+ method: 'POST',
5677
+ path: '/api/extensions/:extensionId/data/migrate',
5678
+ params: extensionParam,
5679
+ request: ExtensionDataMigrationInputSchema,
5680
+ response: z.object({ snapshotId: z.string(), preview: ExtensionDataPreviewSchema }).strict(),
5681
+ error: HostApiErrorSchema,
5682
+ }),
5683
+ exportExtensionData: defineContract({
5684
+ method: 'GET',
5685
+ timeoutMs: 300_000,
5686
+ path: '/api/extensions/:extensionId/data/export',
5687
+ params: extensionParam,
5688
+ request: NoRequestBodySchema,
5689
+ responseFormat: 'bytes',
5690
+ response: z.instanceof(Uint8Array),
5691
+ error: HostApiErrorSchema,
5692
+ }),
5693
+ /** The same package with the host and agent configuration; secrets are left out. */
5694
+ exportExtensionDataWithConfig: defineContract({
5695
+ method: 'GET',
5696
+ timeoutMs: 300_000,
5697
+ path: '/api/extensions/:extensionId/data/export-config',
5698
+ params: extensionParam,
5699
+ request: NoRequestBodySchema,
5700
+ responseFormat: 'bytes',
5701
+ response: z.instanceof(Uint8Array),
5702
+ error: HostApiErrorSchema,
5703
+ }),
5704
+ createExtensionDataSnapshot: defineContract({
5705
+ method: 'POST',
5706
+ path: '/api/extensions/:extensionId/data/snapshots',
5707
+ params: extensionParam,
5708
+ request: z.object({ label: z.string().trim().min(1).max(80) }).strict(),
5709
+ response: z.object({ snapshotId: z.string() }).strict(),
5710
+ error: HostApiErrorSchema,
5711
+ }),
5712
+ inspectExtensionDataPackage: defineContract({
5713
+ timeoutMs: 300_000,
5714
+ method: 'POST',
5715
+ path: '/api/extensions/data/inspect',
5716
+ params: EmptyParamsSchema,
5717
+ request: BinaryUploadRequestSchema,
5718
+ encodeRequest: encodeBinaryUpload,
5719
+ response: ExtensionDataPackageInspectionSchema,
5720
+ error: HostApiErrorSchema,
5721
+ }),
5722
+ listExtensionRequests: defineContract({
5723
+ method: 'GET',
5724
+ path: '/api/extension-requests',
5725
+ params: EmptyParamsSchema,
5726
+ request: NoRequestBodySchema,
5727
+ response: z.object({ requests: z.array(ExtensionRequestSchema) }).strict(),
5728
+ error: HostApiErrorSchema,
5729
+ }),
5730
+ approveExtensionRequest: defineContract({
5731
+ invalidatesSnapshot: true,
5732
+ timeoutMs: 300_000,
5733
+ method: 'POST',
5734
+ path: '/api/extension-requests/:number/approve',
5735
+ params: z.object({ number: z.coerce.number().int().positive() }).strict(),
5736
+ request: NoRequestBodySchema,
5737
+ response: z.object({ message: z.string() }).strict(),
5738
+ error: HostApiErrorSchema,
5739
+ }),
5740
+ rejectExtensionRequest: defineContract({
5741
+ method: 'POST',
5742
+ path: '/api/extension-requests/:number/reject',
5743
+ params: z.object({ number: z.coerce.number().int().positive() }).strict(),
5744
+ request: z.object({ reason: z.string().trim().max(500).optional() }).strict(),
5745
+ response: z.object({ ok: z.literal(true) }).strict(),
5746
+ error: HostApiErrorSchema,
5747
+ }),
5748
+ listAdministrators: defineContract({
5749
+ method: 'GET',
5750
+ path: '/api/administrators',
5751
+ params: EmptyParamsSchema,
5752
+ request: NoRequestBodySchema,
5753
+ response: z.object({ administrators: z.array(AdministratorSchema) }).strict(),
5754
+ error: HostApiErrorSchema,
5755
+ }),
5756
+ addAdministrator: defineContract({
5757
+ method: 'POST',
5758
+ path: '/api/administrators',
5759
+ params: EmptyParamsSchema,
5760
+ request: z.object({ identityId: PlatformIdentityIdSchema }).strict(),
5761
+ response: AdministratorSchema,
5762
+ error: HostApiErrorSchema,
5763
+ }),
5764
+ removeAdministrator: defineContract({
5765
+ method: 'POST',
5766
+ path: '/api/administrators/remove',
5767
+ params: EmptyParamsSchema,
5768
+ request: z.object({ connectionId: ConnectionIdSchema, platformUserId: z.string().min(1) }).strict(),
5769
+ response: z.object({ ok: z.literal(true) }).strict(),
5770
+ error: HostApiErrorSchema,
5771
+ }),
5772
+ createAdministratorClaimCode: defineContract({
5773
+ method: 'POST',
5774
+ path: '/api/administrators/claim-code',
5775
+ params: EmptyParamsSchema,
5776
+ request: NoRequestBodySchema,
5777
+ response: z.object({ code: z.string(), expiresAt: z.number().int().nonnegative() }).strict(),
5778
+ error: HostApiErrorSchema,
5779
+ }),
5780
+ dismissCommunityRelease: defineContract({
5781
+ method: 'POST',
5782
+ path: '/api/community/sync/:extensionId/dismiss',
5783
+ params: extensionParam,
5784
+ request: z.object({ releaseId: CommunityReleaseIdSchema.nullable() }).strict(),
5785
+ response: z.object({ ok: z.literal(true) }).strict(),
5786
+ error: HostApiErrorSchema,
5787
+ }),
5788
+ updateFromCommunity: defineContract({
5789
+ invalidatesSnapshot: true,
5790
+ timeoutMs: 300_000,
5791
+ method: 'POST',
5792
+ path: '/api/community/sync/:extensionId/update',
5793
+ params: extensionParam,
5794
+ request: NoRequestBodySchema,
5795
+ response: z.object({ message: z.string() }).strict(),
5796
+ error: HostApiErrorSchema,
5797
+ }),
5798
+ archiveAuthoringTask: defineContract({
5799
+ invalidatesSnapshot: true,
5800
+ method: 'POST',
5801
+ path: '/api/authoring/tasks/:taskId/archive',
5802
+ params: z.object({ taskId: AuthoringTaskIdSchema }).strict(),
5803
+ request: NoRequestBodySchema,
5804
+ response: z.object({ ok: z.literal(true) }).strict(),
5805
+ error: HostApiErrorSchema,
5806
+ }),
4117
5807
  } as const
4118
5808
 
4119
5809
  export type HostApiContractName = keyof typeof HostApiContracts
@@ -4147,9 +5837,11 @@ const buildValidatedHostApiPath = (
4147
5837
  const consumed = new Set<string>()
4148
5838
  const pathname = contract.path.replace(pathParameterPattern, (_placeholder, key: string) => {
4149
5839
  const value = params[key]
4150
- if (typeof value !== 'string') throw new TypeError(`Host API path parameter ${key} must be a string.`)
5840
+ if (typeof value !== 'string' && typeof value !== 'number') {
5841
+ throw new TypeError(`Host API path parameter ${key} must be a string or number.`)
5842
+ }
4151
5843
  consumed.add(key)
4152
- return encodeURIComponent(value)
5844
+ return encodeURIComponent(String(value))
4153
5845
  })
4154
5846
  const query = new URLSearchParams()
4155
5847
  for (const [key, value] of Object.entries(params)) {
@@ -4173,3 +5865,21 @@ export function buildHostApiContractPath<Params extends AnySchema>(
4173
5865
  export function buildHostApiPath<Name extends HostApiContractName>(name: Name, input: HostApiParams<Name>): string {
4174
5866
  return buildValidatedHostApiPath(HostApiContracts[name], input)
4175
5867
  }
5868
+ import {
5869
+ CommunityFeedbackDraftIdSchema,
5870
+ CommunityFeedbackDraftInputSchema,
5871
+ CommunityFeedbackDraftSchema,
5872
+ CommunityFeedbackDraftUpdateSchema,
5873
+ CommunityFeedbackLastPayloadSchema,
5874
+ CommunityFeedbackLocalListSchema,
5875
+ CommunityFeedbackPayloadSchema,
5876
+ CommunityFeedbackSettingsSchema,
5877
+ CommunityFeedbackSettingsUpdateSchema,
5878
+ CommunityFeedbackSnapshotSchema,
5879
+ } from './community-feedback-host.js'
5880
+ import {
5881
+ CommunityFeedbackRefSchema,
5882
+ CommunityFeedbackSchema,
5883
+ CommunityFeedbackWithdrawSchema,
5884
+ CommunityFeedbackReopenSchema,
5885
+ } from './community-feedback.js'