@nekro-nxt/contracts 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/host-api.ts CHANGED
@@ -292,6 +292,10 @@ const AgentCapabilitiesSchema = z
292
292
  unrestrictedFileAccess: z.boolean(),
293
293
  /** Absent in older clients means on. */
294
294
  scheduledTasks: z.boolean().default(true),
295
+ /** Tools are called from one TypeScript program (`run_code`); takes effect only with `developmentShell`. */
296
+ codeRun: z.boolean().default(false),
297
+ /** Network for commands; absent in older clients means on. */
298
+ commandNetwork: z.boolean().default(true),
295
299
  })
296
300
  .strict()
297
301
 
@@ -386,9 +390,14 @@ const ReviseAgentRequestSchema = AgentRevisionRequestContentSchema.extend({
386
390
  validatePersonaDocumentProjection(value, context)
387
391
  })
388
392
 
389
- // The default that fills `scheduledTasks` for older clients must not turn it on in a partial update.
393
+ // The defaults that fill `scheduledTasks`, `codeRun` and `commandNetwork` for older clients must not reset them in a
394
+ // partial update.
390
395
  const UpdateAgentCapabilitiesRequestSchema = AgentCapabilitiesSchema.partial()
391
- .extend({ scheduledTasks: z.boolean().optional() })
396
+ .extend({
397
+ scheduledTasks: z.boolean().optional(),
398
+ codeRun: z.boolean().optional(),
399
+ commandNetwork: z.boolean().optional(),
400
+ })
392
401
  .strict()
393
402
  .refine((value) => Object.values(value).some((entry) => entry !== undefined), '至少提供一个能力。')
394
403
 
@@ -570,17 +579,25 @@ export const ChannelRuntimeUsageSchema = z
570
579
  })
571
580
  .strict()
572
581
 
582
+ const channelRuntimeToolFields = {
583
+ callId: NonEmptyStringSchema,
584
+ name: NonEmptyStringSchema,
585
+ displayName: NonEmptyStringSchema,
586
+ state: z.enum(['running', 'succeeded', 'failed']),
587
+ inputPreview: z.string().optional(),
588
+ resultPreview: z.string().optional(),
589
+ wroteToChannel: z.boolean().optional(),
590
+ deliveryState: z.enum(['sent', 'partially-sent', 'failed', 'unknown']).optional(),
591
+ durationMs: z.number().int().nonnegative().optional(),
592
+ }
593
+
573
594
  export const ChannelRuntimeToolSchema = z
574
595
  .object({
575
- callId: NonEmptyStringSchema,
576
- name: NonEmptyStringSchema,
577
- displayName: NonEmptyStringSchema,
578
- state: z.enum(['running', 'succeeded', 'failed']),
579
- inputPreview: z.string().optional(),
580
- resultPreview: z.string().optional(),
581
- wroteToChannel: z.boolean().optional(),
582
- deliveryState: z.enum(['sent', 'partially-sent', 'failed', 'unknown']).optional(),
583
- durationMs: z.number().int().nonnegative().optional(),
596
+ ...channelRuntimeToolFields,
597
+ /** Source of a `run_code` program. */
598
+ code: z.string().optional(),
599
+ /** Tools a `run_code` program called, in the order they started. */
600
+ children: z.array(z.object(channelRuntimeToolFields).strict()).optional(),
584
601
  })
585
602
  .strict()
586
603
 
@@ -647,6 +664,8 @@ export const ChannelRuntimeOccupancySchema = z
647
664
  })
648
665
  .strict()
649
666
  .optional(),
667
+ /** Pictures in the conversation; their tokens are not in the breakdown, so they make up most of the rest. */
668
+ imageCount: z.number().int().nonnegative().optional(),
650
669
  })
651
670
  .strict()
652
671
 
@@ -722,6 +741,54 @@ export const ChannelRuntimePerformanceSchema = z
722
741
  })
723
742
  .strict()
724
743
 
744
+ /** What the agent remembered or looked up, newest first; the admin sees it, the model does not. */
745
+ export const ChannelMemoryActivitySchema = z.discriminatedUnion('kind', [
746
+ z
747
+ .object({
748
+ kind: z.literal('backlog-folded'),
749
+ at: z.number().nonnegative().optional(),
750
+ foldedCount: z.number().int().nonnegative(),
751
+ shownCount: z.number().int().nonnegative(),
752
+ foldedImageCount: z.number().int().nonnegative(),
753
+ })
754
+ .strict(),
755
+ z
756
+ .object({
757
+ kind: z.literal('history-search'),
758
+ at: z.number().nonnegative().optional(),
759
+ query: z.string(),
760
+ hits: z.number().int().nonnegative(),
761
+ sender: z.string().optional(),
762
+ })
763
+ .strict(),
764
+ z
765
+ .object({
766
+ kind: z.literal('notes-updated'),
767
+ at: z.number().nonnegative().optional(),
768
+ revision: z.number().int().nonnegative(),
769
+ chars: z.number().int().nonnegative(),
770
+ })
771
+ .strict(),
772
+ z
773
+ .object({
774
+ kind: z.literal('member-notes-updated'),
775
+ at: z.number().nonnegative().optional(),
776
+ memberId: z.string(),
777
+ name: z.string().optional(),
778
+ chars: z.number().int().nonnegative(),
779
+ })
780
+ .strict(),
781
+ z
782
+ .object({
783
+ kind: z.literal('idle-review'),
784
+ at: z.number().nonnegative().optional(),
785
+ quietMinutes: z.number().int().nonnegative(),
786
+ })
787
+ .strict(),
788
+ ])
789
+
790
+ export type ChannelMemoryActivity = z.output<typeof ChannelMemoryActivitySchema>
791
+
725
792
  export const ChannelRuntimeProjectionSchema = z
726
793
  .object({
727
794
  channelId: ChannelIdSchema,
@@ -733,6 +800,7 @@ export const ChannelRuntimeProjectionSchema = z
733
800
  occupancy: ChannelRuntimeOccupancySchema.optional(),
734
801
  cache: ChannelRuntimeCacheSchema.optional(),
735
802
  performance: ChannelRuntimePerformanceSchema.optional(),
803
+ memory: z.array(ChannelMemoryActivitySchema).optional(),
736
804
  turns: z.array(ChannelRuntimeTurnSchema),
737
805
  })
738
806
  .strict()
@@ -774,11 +842,10 @@ export const ChannelRuntimeContextSchema = z
774
842
  })
775
843
  .strict()
776
844
 
777
- /** A channel's own instructions for whoever answers it, with recent earlier versions to restore. */
778
- export const ChannelPromptViewSchema = z
845
+ const ChannelPromptPartSchema = z
779
846
  .object({
780
847
  document: PromptDocumentV1Schema,
781
- /** The agent may not rewrite a locked prompt. */
848
+ /** Notes only: the agent may not rewrite them. */
782
849
  locked: z.boolean(),
783
850
  /** 0 before the first save; send it back as `expectedRevision`. */
784
851
  revision: z.number().int().nonnegative(),
@@ -798,6 +865,146 @@ export const ChannelPromptViewSchema = z
798
865
  })
799
866
  .strict()
800
867
 
868
+ /**
869
+ * What the agent answering a channel reads about it, each part with recent earlier versions to restore: the admin's
870
+ * instructions (system prompt) and the agent's own notes (runtime context).
871
+ */
872
+ export const ChannelPromptViewSchema = z
873
+ .object({ instructions: ChannelPromptPartSchema, notes: ChannelPromptPartSchema })
874
+ .strict()
875
+
876
+ /**
877
+ * How much of a channel's unread backlog reaches the agent at once, and when it looks back on its own. Uncertain
878
+ * trade-offs stay per channel: a busy meme group and a long tabletop session want different budgets.
879
+ */
880
+ export const ChannelContextPolicySchema = z
881
+ .object({
882
+ /** Text characters of a backlog read message by message; older messages collapse into one line. 0: no limit. */
883
+ backlogTextChars: z.number().int().nonnegative().max(1_000_000),
884
+ /** Backlog images shown as pictures, newest first; the rest stay references the agent can open. */
885
+ backlogImages: z.number().int().nonnegative().max(20),
886
+ /** Quiet minutes after which the agent reviews the conversation and updates its notes. 0: off. */
887
+ idleReviewMinutes: z
888
+ .number()
889
+ .int()
890
+ .nonnegative()
891
+ .max(24 * 60),
892
+ })
893
+ .strict()
894
+
895
+ export type ChannelContextPolicy = z.output<typeof ChannelContextPolicySchema>
896
+
897
+ export const DEFAULT_CHANNEL_CONTEXT_POLICY: ChannelContextPolicy = Object.freeze({
898
+ backlogTextChars: 40_000,
899
+ backlogImages: 6,
900
+ idleReviewMinutes: 45,
901
+ })
902
+
903
+ export const ChannelContextPolicyViewSchema = z
904
+ .object({
905
+ policy: ChannelContextPolicySchema,
906
+ defaults: ChannelContextPolicySchema,
907
+ /** False while the channel follows the defaults. */
908
+ custom: z.boolean(),
909
+ })
910
+ .strict()
911
+
912
+ export type ChannelContextPolicyView = z.output<typeof ChannelContextPolicyViewSchema>
913
+
914
+ /** Whether a newer release exists on the build's own channel; development builds are never compared. */
915
+ export const ProductUpdateStatusSchema = z
916
+ .object({
917
+ channel: z.enum(['stable', 'preview', 'development']),
918
+ currentVersion: z.string(),
919
+ /** Short commit of a release build. */
920
+ currentCommit: z.string().optional(),
921
+ state: z.enum(['unknown', 'up-to-date', 'available', 'failed', 'unsupported']),
922
+ latest: z
923
+ .object({
924
+ version: z.string(),
925
+ commit: z.string().optional(),
926
+ url: z.string().url(),
927
+ publishedAt: z.number().int().nonnegative().optional(),
928
+ })
929
+ .strict()
930
+ .optional(),
931
+ checkedAt: z.number().int().nonnegative().optional(),
932
+ error: z.string().optional(),
933
+ autoCheck: z.boolean(),
934
+ })
935
+ .strict()
936
+
937
+ export type ProductUpdateStatus = z.output<typeof ProductUpdateStatusSchema>
938
+
939
+ /** Pause between consecutive messages an agent sends to one channel; longer messages wait a little longer. */
940
+ export const MessagePacingSchema = z.enum(['off', 'fast', 'normal', 'slow'])
941
+
942
+ export type MessagePacing = z.output<typeof MessagePacingSchema>
943
+
944
+ export const DEFAULT_MESSAGE_PACING: MessagePacing = 'normal'
945
+
946
+ export const MessagePacingSettingsSchema = z.object({ pacing: MessagePacingSchema }).strict()
947
+
948
+ /** `keyword`: SQLite keyword search only; `builtin`: keywords fused with the built-in semantic model. */
949
+ export const RetrievalModeSchema = z.enum(['keyword', 'builtin'])
950
+ export type RetrievalMode = z.output<typeof RetrievalModeSchema>
951
+
952
+ /** Search used by extension indexes (表情包与扩展素材能力 §6.4). */
953
+ export const RetrievalStatusSchema = z
954
+ .object({
955
+ mode: RetrievalModeSchema,
956
+ builtin: z
957
+ .object({
958
+ model: z.string(),
959
+ /** False where no inference runtime is published for this system and processor. */
960
+ supported: z.boolean(),
961
+ downloadBytes: z.number().int().nonnegative(),
962
+ install: z.discriminatedUnion('state', [
963
+ z.object({ state: z.literal('not-installed') }).strict(),
964
+ z
965
+ .object({
966
+ state: z.literal('downloading'),
967
+ receivedBytes: z.number().int().nonnegative(),
968
+ totalBytes: z.number().int().nonnegative(),
969
+ })
970
+ .strict(),
971
+ z.object({ state: z.literal('installed') }).strict(),
972
+ z.object({ state: z.literal('failed'), error: z.string() }).strict(),
973
+ ]),
974
+ })
975
+ .strict(),
976
+ vectors: z
977
+ .object({
978
+ documents: z.number().int().nonnegative(),
979
+ embedded: z.number().int().nonnegative(),
980
+ state: z.enum(['idle', 'running', 'ready']),
981
+ error: z.string().optional(),
982
+ })
983
+ .strict(),
984
+ })
985
+ .strict()
986
+ export type RetrievalStatus = z.output<typeof RetrievalStatusSchema>
987
+
988
+ /** What the agent keeps about individual members of one channel; each note comes with that member's messages. */
989
+ export const ChannelMemberNotesViewSchema = z
990
+ .object({
991
+ notes: z.array(
992
+ z
993
+ .object({
994
+ memberId: ChannelMemberIdSchema,
995
+ displayName: z.string().optional(),
996
+ text: z.string(),
997
+ updatedBy: z.enum(['admin', 'agent']),
998
+ updatedAt: z.number().int().nonnegative(),
999
+ })
1000
+ .strict(),
1001
+ ),
1002
+ maxChars: z.number().int().positive(),
1003
+ })
1004
+ .strict()
1005
+
1006
+ export type ChannelMemberNotesView = z.output<typeof ChannelMemberNotesViewSchema>
1007
+
801
1008
  export type ChannelRuntimePhase = z.output<typeof ChannelRuntimePhaseSchema>
802
1009
  export type ChannelRuntimeUsage = z.output<typeof ChannelRuntimeUsageSchema>
803
1010
  export type ChannelRuntimeOccupancy = z.output<typeof ChannelRuntimeOccupancySchema>
@@ -839,6 +1046,7 @@ const AdapterConnectionDescriptorSchema = z
839
1046
  icon: HostIconNameSchema.optional(),
840
1047
  triggerable: z.boolean(),
841
1048
  channelKinds: z.array(z.enum(['internal', 'direct', 'group'])).optional(),
1049
+ directedAt: z.enum(['member', 'message']).optional(),
842
1050
  })
843
1051
  .strict(),
844
1052
  ),
@@ -1082,6 +1290,27 @@ export const ScheduledTaskSchema = z
1082
1290
 
1083
1291
  export type ScheduledTask = z.output<typeof ScheduledTaskSchema>
1084
1292
 
1293
+ /** The Node that runs `run_code` programs, and the download the desktop app offers when there is none. */
1294
+ export const CodeRunAvailabilitySchema = z
1295
+ .object({
1296
+ available: z.boolean(),
1297
+ source: z.enum(['host', 'system', 'downloaded']).optional(),
1298
+ version: z.string().optional(),
1299
+ download: z
1300
+ .object({
1301
+ version: z.string(),
1302
+ state: z.enum(['idle', 'downloading', 'failed']),
1303
+ receivedBytes: z.number().int().nonnegative().optional(),
1304
+ totalBytes: z.number().int().nonnegative().optional(),
1305
+ error: z.string().optional(),
1306
+ })
1307
+ .strict()
1308
+ .optional(),
1309
+ })
1310
+ .strict()
1311
+
1312
+ export type CodeRunAvailability = z.output<typeof CodeRunAvailabilitySchema>
1313
+
1085
1314
  export const HostSnapshotSchema = z
1086
1315
  .object({
1087
1316
  upgrade: HostUpgradeSummarySchema.optional(),
@@ -1114,6 +1343,10 @@ export const HostSnapshotSchema = z
1114
1343
  capabilityAvailability: z
1115
1344
  .object({
1116
1345
  subagents: z.object({ available: z.boolean() }).strict(),
1346
+ /** Optional in older hosts, which never offer `run_code`. */
1347
+ codeRun: CodeRunAvailabilitySchema.optional(),
1348
+ /** What this host can confine for commands beyond file writes; optional in older hosts. */
1349
+ commandConfinement: z.object({ readScope: z.boolean(), networkControl: z.boolean() }).strict().optional(),
1117
1350
  webSearch: z
1118
1351
  .object({
1119
1352
  provider: z.literal('deepseek-official'),
@@ -1310,7 +1543,7 @@ export const HostSnapshotSchema = z
1310
1543
  .regex(/^\/api\/extensions\/[^/]+\/revisions\/[^/]+\/icon\/[a-f0-9]{64}\.(?:svg|png|webp)$/u)
1311
1544
  .optional(),
1312
1545
  createdAt: z.number().int().safe().nonnegative(),
1313
- /** 从社区安装的保存记录的来源;本机保存与文件导入没有来源。 */
1546
+ /** 从社区安装的版本的来源;本机保存与文件导入没有来源。 */
1314
1547
  source: CommunitySourceSchema.optional(),
1315
1548
  provides: z.array(ExtensionProvideSchema),
1316
1549
  /** Whether this Revision can be enabled for agents (agent-layer contributions or capabilities). */
@@ -2415,7 +2648,9 @@ export const HostApiContracts = {
2415
2648
  params: channelParam,
2416
2649
  request: z
2417
2650
  .object({
2651
+ kind: z.enum(['instructions', 'notes']),
2418
2652
  document: PromptDocumentV1Schema,
2653
+ /** Notes only; ignored for instructions. */
2419
2654
  locked: z.boolean(),
2420
2655
  /** The revision the edit started from; a newer stored revision rejects the save. */
2421
2656
  expectedRevision: z.number().int().nonnegative(),
@@ -2424,6 +2659,130 @@ export const HostApiContracts = {
2424
2659
  response: ChannelPromptViewSchema,
2425
2660
  error: HostApiErrorSchema,
2426
2661
  }),
2662
+ getProductUpdates: defineContract({
2663
+ method: 'GET',
2664
+ path: '/api/product/updates',
2665
+ params: EmptyParamsSchema,
2666
+ request: NoRequestBodySchema,
2667
+ response: ProductUpdateStatusSchema,
2668
+ error: HostApiErrorSchema,
2669
+ }),
2670
+ checkProductUpdates: defineContract({
2671
+ method: 'POST',
2672
+ path: '/api/product/updates/check',
2673
+ params: EmptyParamsSchema,
2674
+ request: NoRequestBodySchema,
2675
+ response: ProductUpdateStatusSchema,
2676
+ error: HostApiErrorSchema,
2677
+ }),
2678
+ updateProductUpdateSettings: defineContract({
2679
+ method: 'PUT',
2680
+ path: '/api/product/updates/settings',
2681
+ params: EmptyParamsSchema,
2682
+ request: z.object({ autoCheck: z.boolean() }).strict(),
2683
+ response: ProductUpdateStatusSchema,
2684
+ error: HostApiErrorSchema,
2685
+ }),
2686
+ getMessagePacingSettings: defineContract({
2687
+ method: 'GET',
2688
+ path: '/api/settings/message-pacing',
2689
+ params: EmptyParamsSchema,
2690
+ request: NoRequestBodySchema,
2691
+ response: MessagePacingSettingsSchema,
2692
+ error: HostApiErrorSchema,
2693
+ }),
2694
+ updateMessagePacingSettings: defineContract({
2695
+ method: 'PUT',
2696
+ path: '/api/settings/message-pacing',
2697
+ params: EmptyParamsSchema,
2698
+ request: MessagePacingSettingsSchema,
2699
+ response: MessagePacingSettingsSchema,
2700
+ error: HostApiErrorSchema,
2701
+ }),
2702
+ getRetrievalStatus: defineContract({
2703
+ method: 'GET',
2704
+ path: '/api/settings/retrieval',
2705
+ params: EmptyParamsSchema,
2706
+ request: NoRequestBodySchema,
2707
+ response: RetrievalStatusSchema,
2708
+ error: HostApiErrorSchema,
2709
+ }),
2710
+ updateRetrievalMode: defineContract({
2711
+ method: 'PUT',
2712
+ path: '/api/settings/retrieval',
2713
+ params: EmptyParamsSchema,
2714
+ request: z.object({ mode: RetrievalModeSchema }).strict(),
2715
+ response: RetrievalStatusSchema,
2716
+ error: HostApiErrorSchema,
2717
+ }),
2718
+ downloadRetrievalModel: defineContract({
2719
+ method: 'POST',
2720
+ path: '/api/settings/retrieval/model/download',
2721
+ params: EmptyParamsSchema,
2722
+ request: NoRequestBodySchema,
2723
+ response: RetrievalStatusSchema,
2724
+ error: HostApiErrorSchema,
2725
+ }),
2726
+ removeRetrievalModel: defineContract({
2727
+ method: 'DELETE',
2728
+ path: '/api/settings/retrieval/model',
2729
+ params: EmptyParamsSchema,
2730
+ request: NoRequestBodySchema,
2731
+ response: RetrievalStatusSchema,
2732
+ error: HostApiErrorSchema,
2733
+ }),
2734
+ downloadCodeRunNode: defineContract({
2735
+ invalidatesSnapshot: true,
2736
+ method: 'POST',
2737
+ path: '/api/runtimes/code-run-node/download',
2738
+ params: EmptyParamsSchema,
2739
+ request: NoRequestBodySchema,
2740
+ response: CodeRunAvailabilitySchema,
2741
+ error: HostApiErrorSchema,
2742
+ }),
2743
+ removeCodeRunNode: defineContract({
2744
+ invalidatesSnapshot: true,
2745
+ method: 'DELETE',
2746
+ path: '/api/runtimes/code-run-node',
2747
+ params: EmptyParamsSchema,
2748
+ request: NoRequestBodySchema,
2749
+ response: CodeRunAvailabilitySchema,
2750
+ error: HostApiErrorSchema,
2751
+ }),
2752
+ getChannelMemberNotes: defineContract({
2753
+ method: 'GET',
2754
+ path: '/api/channels/:channelId/member-notes',
2755
+ params: channelParam,
2756
+ request: NoRequestBodySchema,
2757
+ response: ChannelMemberNotesViewSchema,
2758
+ error: HostApiErrorSchema,
2759
+ }),
2760
+ updateChannelMemberNote: defineContract({
2761
+ method: 'PUT',
2762
+ path: '/api/channels/:channelId/member-notes/:memberId',
2763
+ params: z.object({ channelId: ChannelIdSchema, memberId: ChannelMemberIdSchema }).strict(),
2764
+ /** An empty text forgets the member. */
2765
+ request: z.object({ text: z.string().max(2000) }).strict(),
2766
+ response: ChannelMemberNotesViewSchema,
2767
+ error: HostApiErrorSchema,
2768
+ }),
2769
+ getChannelContextPolicy: defineContract({
2770
+ method: 'GET',
2771
+ path: '/api/channels/:channelId/context-policy',
2772
+ params: channelParam,
2773
+ request: NoRequestBodySchema,
2774
+ response: ChannelContextPolicyViewSchema,
2775
+ error: HostApiErrorSchema,
2776
+ }),
2777
+ updateChannelContextPolicy: defineContract({
2778
+ method: 'PUT',
2779
+ path: '/api/channels/:channelId/context-policy',
2780
+ params: channelParam,
2781
+ /** `null` returns the channel to the defaults. */
2782
+ request: z.object({ policy: ChannelContextPolicySchema.nullable() }).strict(),
2783
+ response: ChannelContextPolicyViewSchema,
2784
+ error: HostApiErrorSchema,
2785
+ }),
2427
2786
  resetChannelContext: defineContract({
2428
2787
  invalidatesSnapshot: true,
2429
2788
  method: 'POST',