@nekro-nxt/contracts 0.5.0 → 0.7.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/index.ts CHANGED
@@ -5,6 +5,8 @@ export * from './host-api.js'
5
5
  export * from './management-api.js'
6
6
  export * from './runtime-compatibility.js'
7
7
  export * from './extension-capabilities.js'
8
+ export * from './credentials.js'
9
+ export * from './linked-accounts.js'
8
10
  export * from './community.js'
9
11
  export * from './community-personas.js'
10
12
 
@@ -12,3 +14,4 @@ export * from './commands.js'
12
14
  export * from './logs.js'
13
15
  export * from './community-feedback.js'
14
16
  export * from './community-feedback-host.js'
17
+ export * from './response-timing.js'
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod'
2
+ import { AgentIdSchema, ChannelIdSchema, LinkedAccountIdSchema } from './domain.js'
3
+
4
+ /**
5
+ * Linked accounts (设置 → 关联账号): third-party accounts that agents' commands act as. The library only keeps them;
6
+ * an agent's commands receive an account only through its `commandAccounts` grant (命令账号授权 A1、A2). Tokens are
7
+ * write-only; every view below carries metadata only.
8
+ */
9
+
10
+ /** Platforms the host can link accounts of; each grant names one account per platform. */
11
+ export const LinkedAccountPlatformIdSchema = z.enum(['github'])
12
+ export type LinkedAccountPlatformId = z.output<typeof LinkedAccountPlatformIdSchema>
13
+
14
+ /** How an account is added: a typed token, or the token of a login the platform's local CLI holds (read once). */
15
+ export const LinkedAccountMethodSchema = z.enum(['token', 'gh-login'])
16
+ export type LinkedAccountMethod = z.output<typeof LinkedAccountMethodSchema>
17
+
18
+ /** A login the local `gh` holds, offered as a quick way to link a GitHub account. */
19
+ export const LocalGithubLoginSchema = z.object({ login: z.string().trim().min(1), active: z.boolean() }).strict()
20
+
21
+ const tokenFields = { method: z.literal('token'), token: z.string().trim().min(1).max(512) }
22
+ const ghLoginFields = { method: z.literal('gh-login'), login: z.string().trim().min(1).max(128) }
23
+
24
+ /** Where a token comes from: typed, or read once from a login of the platform's local CLI. */
25
+ export const LinkedAccountTokenSourceSchema = z.discriminatedUnion('method', [
26
+ z.object(tokenFields).strict(),
27
+ z.object(ghLoginFields).strict(),
28
+ ])
29
+ export type LinkedAccountTokenSource = z.output<typeof LinkedAccountTokenSourceSchema>
30
+
31
+ export const LinkedAccountViewSchema = z
32
+ .object({
33
+ id: LinkedAccountIdSchema,
34
+ platform: LinkedAccountPlatformIdSchema,
35
+ /** The account name on the platform, as the platform reported it when the token was verified. */
36
+ login: z.string(),
37
+ /** Token scopes where the platform reports them (GitHub classic tokens); `null` otherwise. */
38
+ scopes: z.array(z.string()).nullable(),
39
+ source: LinkedAccountMethodSchema,
40
+ /** False when the stored token cannot be read any more; the account stays so it can be replaced or removed. */
41
+ available: z.boolean(),
42
+ /** Agents whose capabilities grant this account. */
43
+ grantedAgentIds: z.array(AgentIdSchema),
44
+ createdAt: z.number().int().nonnegative(),
45
+ updatedAt: z.number().int().nonnegative(),
46
+ lastUsedAt: z.number().int().nonnegative().nullable(),
47
+ })
48
+ .strict()
49
+ export type LinkedAccountView = z.output<typeof LinkedAccountViewSchema>
50
+
51
+ /** Links an account: the platform plus how its token is given. */
52
+ export const AddLinkedAccountRequestSchema = z.discriminatedUnion('method', [
53
+ z.object({ platform: LinkedAccountPlatformIdSchema, ...tokenFields }).strict(),
54
+ z.object({ platform: LinkedAccountPlatformIdSchema, ...ghLoginFields }).strict(),
55
+ ])
56
+ export type AddLinkedAccountRequest = z.output<typeof AddLinkedAccountRequestSchema>
57
+
58
+ /** A new token for an account; it must belong to the same account on the platform. */
59
+ export const ReplaceLinkedAccountTokenRequestSchema = LinkedAccountTokenSourceSchema
60
+ export type ReplaceLinkedAccountTokenRequest = z.output<typeof ReplaceLinkedAccountTokenRequestSchema>
61
+
62
+ /** Removing a granted account needs `confirm`; without it the result lists the agents it is granted to. */
63
+ export const RemoveLinkedAccountRequestSchema = z.object({ confirm: z.boolean().default(false) }).strict()
64
+
65
+ /** One recorded use: an agent's command environment carried the account. Newest 500 per account, none over 90 days. */
66
+ export const LinkedAccountUseSchema = z
67
+ .object({
68
+ at: z.number().int().nonnegative(),
69
+ agentId: AgentIdSchema.nullable(),
70
+ channelId: ChannelIdSchema.nullable(),
71
+ consumerKind: z.enum(['command']),
72
+ consumerId: z.string(),
73
+ })
74
+ .strict()
75
+ export type LinkedAccountUse = z.output<typeof LinkedAccountUseSchema>
76
+
77
+ export const LinkedAccountUsesViewSchema = z.object({ uses: z.array(LinkedAccountUseSchema) }).strict()
@@ -124,7 +124,7 @@ export const ClientNotificationSchema = z
124
124
  route: z
125
125
  .string()
126
126
  .regex(
127
- /^\/(?:(?:live|channels|agents|workshop|wiring|settings|community|apps|work|connections|users|extensions)(?:\/[^?#]*)?)?$/u,
127
+ /^\/(?:(?:live|channels|agents|workshop|wiring|settings|community|apps|work|connections|users|extensions)(?:\/[^?#]*)?)?(?:\?[^#]*)?$/u,
128
128
  )
129
129
  .optional(),
130
130
  })
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod'
2
+
3
+ /** Bounds of the numeric response timing settings; the host rejects values outside them. */
4
+ export const RESPONSE_TIMING_LIMITS = {
5
+ waitMaxQuietSeconds: { min: 5, max: 300 },
6
+ waitMaxTotalSeconds: { min: 10, max: 900 },
7
+ debounceSeconds: { min: 0, max: 30 },
8
+ debounceMaxSeconds: { min: 1, max: 120 },
9
+ debounceMaxMessages: { min: 1, max: 20 },
10
+ attentionSeconds: { min: 5, max: 600 },
11
+ midWakesPerMinute: { min: 1, max: 30 },
12
+ } as const
13
+
14
+ const bounded = (key: keyof typeof RESPONSE_TIMING_LIMITS) =>
15
+ z.number().int().min(RESPONSE_TIMING_LIMITS[key].min).max(RESPONSE_TIMING_LIMITS[key].max).optional()
16
+
17
+ /**
18
+ * Per-binding timing of when the agent speaks (Decision 2026-10-31 响应时机与智能响应). Every field is optional: an
19
+ * omitted one uses {@link RESPONSE_TIMING_DEFAULTS}. Waiting applies to every policy that answers messages; the rest
20
+ * only to `smart`.
21
+ */
22
+ export const ResponseTimingSettingsSchema = z
23
+ .object({
24
+ /** The agent may end a turn with `waiting-for-more` and be woken when the speaker goes quiet. */
25
+ waitEnabled: z.boolean().optional(),
26
+ /** Longest quiet period one wait may ask for. */
27
+ waitMaxQuietSeconds: bounded('waitMaxQuietSeconds'),
28
+ /** Longest the agent may keep waiting for one person, counted from the first wait. */
29
+ waitMaxTotalSeconds: bounded('waitMaxTotalSeconds'),
30
+ /** Smart: wait for the speaker to stay quiet this long before a turn starts; 0 starts at once. */
31
+ debounceSeconds: bounded('debounceSeconds'),
32
+ /** Smart: start anyway once this long has passed since the first message. */
33
+ debounceMaxSeconds: bounded('debounceMaxSeconds'),
34
+ /** Smart: start anyway once this many messages from the speaker are collected. */
35
+ debounceMaxMessages: bounded('debounceMaxMessages'),
36
+ /** Smart: a message that contains the agent's name or an alias wakes it. */
37
+ nameWake: z.boolean().optional(),
38
+ /** Smart: after someone talks with the agent, their next messages wake it for a while. */
39
+ attentionWake: z.boolean().optional(),
40
+ attentionSeconds: bounded('attentionSeconds'),
41
+ /** Smart: name and attention wakes per channel per minute; strong signals are never limited. */
42
+ midWakesPerMinute: bounded('midWakesPerMinute'),
43
+ })
44
+ .strict()
45
+
46
+ export type ResponseTimingSettings = z.infer<typeof ResponseTimingSettingsSchema>
47
+
48
+ export type ResolvedResponseTiming = {
49
+ readonly [K in keyof ResponseTimingSettings]-?: NonNullable<ResponseTimingSettings[K]>
50
+ }
51
+
52
+ export const RESPONSE_TIMING_DEFAULTS: ResolvedResponseTiming = {
53
+ waitEnabled: true,
54
+ waitMaxQuietSeconds: 60,
55
+ waitMaxTotalSeconds: 120,
56
+ debounceSeconds: 3,
57
+ debounceMaxSeconds: 30,
58
+ debounceMaxMessages: 5,
59
+ nameWake: true,
60
+ attentionWake: true,
61
+ attentionSeconds: 60,
62
+ midWakesPerMinute: 3,
63
+ }
64
+
65
+ /** Shortest quiet period a wait may ask for, whatever the channel allows. */
66
+ export const RESPONSE_WAIT_MIN_QUIET_SECONDS = 5
67
+
68
+ export const resolveResponseTiming = (settings: ResponseTimingSettings | undefined): ResolvedResponseTiming => ({
69
+ ...RESPONSE_TIMING_DEFAULTS,
70
+ ...Object.fromEntries(Object.entries(settings ?? {}).filter(([, value]) => value !== undefined)),
71
+ })
72
+
73
+ /** Extra names that wake the agent in smart mode; the display name always counts too. */
74
+ export const AgentAliasesSchema = z
75
+ .array(z.string().trim().min(1).max(32))
76
+ .max(16)
77
+ .transform((aliases) => [...new Set(aliases)])