@vibe-forge/core 0.4.0 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-forge/core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "imports": {
5
5
  "#~/*.js": {
6
6
  "__vibe-forge__": {
@@ -22,60 +22,61 @@
22
22
  "require": "./dist/index.js"
23
23
  }
24
24
  },
25
- "./channel": {
25
+ "./adapter": {
26
26
  "__vibe-forge__": {
27
- "default": "./src/channel.ts"
27
+ "default": "./src/adapter/index.ts"
28
28
  },
29
29
  "default": {
30
- "import": "./dist/channel.mjs",
31
- "require": "./dist/channel.js"
30
+ "import": "./dist/adapter.mjs",
31
+ "require": "./dist/adapter.js"
32
32
  }
33
33
  },
34
- "./utils/*": {
34
+ "./channel": {
35
35
  "__vibe-forge__": {
36
- "default": "./src/utils/*.ts"
36
+ "default": "./src/channel.ts"
37
37
  },
38
38
  "default": {
39
- "import": "./dist/utils/*.mjs",
40
- "require": "./dist/utils/*.js"
39
+ "import": "./dist/channel.mjs",
40
+ "require": "./dist/channel.js"
41
41
  }
42
42
  },
43
- "./controllers/task": {
43
+ "./schema": {
44
44
  "__vibe-forge__": {
45
- "default": "./src/controllers/task/index.ts"
45
+ "default": "./src/schema.ts"
46
46
  },
47
47
  "default": {
48
- "import": "./dist/controllers/task/index.mjs",
49
- "require": "./dist/controllers/task/index.js"
48
+ "import": "./dist/schema.mjs",
49
+ "require": "./dist/schema.js"
50
50
  }
51
51
  },
52
- "./controllers/benchmark": {
52
+ "./hooks": {
53
53
  "__vibe-forge__": {
54
- "default": "./src/controllers/benchmark/index.ts"
54
+ "default": "./src/hooks/index.ts"
55
55
  },
56
56
  "default": {
57
- "import": "./dist/controllers/benchmark/index.mjs",
58
- "require": "./dist/controllers/benchmark/index.js"
57
+ "import": "./dist/hooks/index.mjs",
58
+ "require": "./dist/hooks/index.js"
59
59
  }
60
60
  },
61
- "./schema": {
61
+ "./utils/*": {
62
62
  "__vibe-forge__": {
63
- "default": "./src/schema.ts"
63
+ "default": "./src/utils/*.ts"
64
64
  },
65
65
  "default": {
66
- "import": "./dist/schema.mjs",
67
- "require": "./dist/schema.js"
66
+ "import": "./dist/utils/*.mjs",
67
+ "require": "./dist/utils/*.js"
68
68
  }
69
69
  },
70
- "./hooks": {
70
+ "./controllers/*": {
71
71
  "__vibe-forge__": {
72
- "default": "./src/hooks/index.ts"
72
+ "default": "./src/controllers/*/index.ts"
73
73
  },
74
74
  "default": {
75
- "import": "./dist/hooks/index.mjs",
76
- "require": "./dist/hooks/index.js"
75
+ "import": "./dist/controllers/*/index.mjs",
76
+ "require": "./dist/controllers/*/index.js"
77
77
  }
78
- }
78
+ },
79
+ "./package.json": "./package.json"
79
80
  },
80
81
  "dependencies": {
81
82
  "fast-glob": "^3.3.3",
package/src/channel.ts CHANGED
@@ -4,12 +4,46 @@ export interface ChannelMap {}
4
4
 
5
5
  export type ChannelType = keyof ChannelMap
6
6
 
7
+ export const channelAccessSchema = z.object({
8
+ // 管理员
9
+ admins: z.array(z.string()).optional().describe(
10
+ '频道管理员账号(sender ID),管理员拥有管理操作权限且不受以下访问控制限制'
11
+ ),
12
+ // 会话类型控制
13
+ allowPrivateChat: z.boolean().optional().describe('是否允许私聊消息,默认 true'),
14
+ allowGroupChat: z.boolean().optional().describe('是否允许群聊消息,默认 true'),
15
+ // 群组访问控制
16
+ allowedGroups: z.array(z.string()).optional().describe('群组白名单(channel ID),设置后仅在指定群中响应'),
17
+ blockedGroups: z.array(z.string()).optional().describe('群组黑名单(channel ID),在指定群中不响应'),
18
+ // 用户访问控制
19
+ allowedSenders: z.array(z.string()).optional().describe('发送者白名单(sender ID),设置后仅白名单内的用户可交互'),
20
+ blockedSenders: z.array(z.string()).optional().describe('发送者黑名单(sender ID),黑名单内的用户消息将被忽略')
21
+ })
22
+
23
+ export type ChannelAccessConfig = z.infer<typeof channelAccessSchema>
24
+
7
25
  export const channelBaseSchema = z.object({
8
- type: z.string().min(1).describe('频道类型'),
9
- title: z.string().optional().describe('频道标题'),
10
- description: z.string().optional().describe('频道说明'),
11
- enabled: z.boolean().optional().describe('是否启用'),
12
- admins: z.array(z.string()).optional().describe('频道管理员账号')
26
+ // 基础配置
27
+ type: z
28
+ .string().min(1)
29
+ .describe('频道类型'),
30
+ title: z
31
+ .string().optional()
32
+ .describe('频道标题'),
33
+ description: z
34
+ .string().optional()
35
+ .describe('频道说明'),
36
+ enabled: z
37
+ .boolean().optional()
38
+ .describe('是否启用'),
39
+ // 会话行为
40
+ systemPrompt: z
41
+ .string().optional()
42
+ .describe('在此频道启动会话时注入的系统提示词'),
43
+ // 访问权限控制
44
+ access: channelAccessSchema
45
+ .optional()
46
+ .describe('频道访问权限配置')
13
47
  })
14
48
 
15
49
  export type ChannelBaseConfig = z.infer<typeof channelBaseSchema>
@@ -25,9 +59,27 @@ export interface ChannelConnection<TMessage> {
25
59
  startReceiving?: (options: {
26
60
  handlers: ChannelEventHandlers
27
61
  }) => Promise<void>
62
+ /**
63
+ * Called when a new session is being created for this channel.
64
+ * The channel implementation can use this to inject channel-specific context
65
+ * (e.g. bot profile fetched from platform API) into the system prompt.
66
+ */
67
+ generateSystemPrompt?: (inbound: ChannelInboundEvent) => Promise<string | undefined>
28
68
  close?: () => Promise<void>
29
69
  }
30
70
 
71
+ export interface ChannelLogger {
72
+ error: (...msg: unknown[]) => void | Promise<void>
73
+ warn: (...msg: unknown[]) => void | Promise<void>
74
+ info: (...msg: unknown[]) => void | Promise<void>
75
+ debug: (...msg: unknown[]) => void | Promise<void>
76
+ trace: (...msg: unknown[]) => void | Promise<void>
77
+ }
78
+
79
+ export interface ChannelConnectionOptions {
80
+ logger?: ChannelLogger
81
+ }
82
+
31
83
  export interface ChannelInboundEvent {
32
84
  channelType: string
33
85
  sessionType: string
@@ -70,6 +122,11 @@ export const defineChannel = <TConfigSchema extends z.ZodTypeAny, TMessageSchema
70
122
  descriptor: ChannelDescriptor<TConfigSchema, TMessageSchema>
71
123
  ) => descriptor
72
124
 
73
- export const defineChannelConnection = <TConfigSchema extends z.ZodTypeAny, TMessageSchema extends z.ZodTypeAny>(
74
- connect: (config: z.infer<TConfigSchema>) => Promise<ChannelConnection<z.infer<TMessageSchema>>>
75
- ) => connect
125
+ export type ChannelCreateFn<TConfig = unknown, TMessage = unknown> = (
126
+ config: TConfig,
127
+ options?: ChannelConnectionOptions
128
+ ) => Promise<ChannelConnection<TMessage>>
129
+
130
+ export const defineCreateChannelConnection = <TConfigSchema extends z.ZodTypeAny, TMessageSchema extends z.ZodTypeAny>(
131
+ connect: ChannelCreateFn<z.infer<TConfigSchema>, z.infer<TMessageSchema>>
132
+ ): ChannelCreateFn<z.infer<TConfigSchema>, z.infer<TMessageSchema>> => connect
@@ -1,8 +1,14 @@
1
- import type { ChannelConfig } from '../channels'
1
+ import type { ChannelConfig } from '../channel'
2
2
  import type { PluginConfig } from '../hooks'
3
3
 
4
4
  export interface AdapterMap {}
5
5
 
6
+ export interface AdapterBuiltinModel {
7
+ value: string
8
+ title: string
9
+ description: string
10
+ }
11
+
6
12
  export interface ModelServiceConfig {
7
13
  /**
8
14
  * 模型服务展示标题
@@ -228,6 +234,7 @@ export interface ConfigSection {
228
234
  modelServices?: Config['modelServices']
229
235
  channels?: Config['channels']
230
236
  adapters?: Config['adapters']
237
+ adapterBuiltinModels?: Record<string, AdapterBuiltinModel[]>
231
238
  plugins?: {
232
239
  plugins?: Config['plugins']
233
240
  enabledPlugins?: Config['enabledPlugins']
@@ -1,7 +1,7 @@
1
1
  import process from 'node:process'
2
2
 
3
- import type { AdapterCtx, AdapterQueryOptions } from '@vibe-forge/core'
4
3
  import { loadConfig } from '@vibe-forge/core'
4
+ import type { AdapterCtx, AdapterQueryOptions } from '@vibe-forge/core/adapter'
5
5
  import { getCache, setCache } from '@vibe-forge/core/utils/cache'
6
6
  import { createLogger } from '@vibe-forge/core/utils/create-logger'
7
7
  import { uuid } from '@vibe-forge/core/utils/uuid'
@@ -1,12 +1,8 @@
1
- import type {
2
- AdapterCtx,
3
- AdapterOutputEvent,
4
- AdapterQueryOptions,
5
- ModelServiceConfig,
6
- TaskDetail
7
- } from '@vibe-forge/core'
8
- import { loadAdapter } from '@vibe-forge/core'
9
- import { callHook } from '@vibe-forge/core/utils/api'
1
+ import type { AdapterCtx, AdapterOutputEvent, AdapterQueryOptions } from '#~/adapter/index.js'
2
+ import { loadAdapter } from '#~/adapter/index.js'
3
+ import type { ModelServiceConfig } from '#~/config.js'
4
+ import type { TaskDetail } from '#~/types.js'
5
+ import { callHook } from '#~/utils/api.js'
10
6
 
11
7
  import { prepare } from './prepare'
12
8
  import type { RunTaskOptions } from './type'
@@ -26,17 +22,29 @@ const resolveQueryModel = (params: {
26
22
  inputModel?: string
27
23
  }) => {
28
24
  const inputModel = normalizeNonEmptyString(params.inputModel)
29
- if (inputModel?.includes(',')) return inputModel
25
+ // User explicitly provided a model → pass through as-is.
26
+ // The adapter decides CCR vs native based on whether it contains ",".
27
+ if (inputModel != null) return inputModel
30
28
 
29
+ // No explicit model → auto-resolve from modelServices config.
30
+ // Produces "service,model" format when services are configured,
31
+ // which signals the adapter to route through CCR.
31
32
  const mergedModelServices = {
32
33
  ...(params.config?.modelServices ?? {}),
33
34
  ...(params.userConfig?.modelServices ?? {})
34
35
  }
35
- const mergedDefaultModel = pickFirstNonEmptyString([params.userConfig?.defaultModel, params.config?.defaultModel])
36
- const mergedDefaultModelService = pickFirstNonEmptyString([
37
- params.userConfig?.defaultModelService,
38
- params.config?.defaultModelService
39
- ])
36
+ const mergedDefaultModel = pickFirstNonEmptyString(
37
+ [
38
+ params.userConfig?.defaultModel,
39
+ params.config?.defaultModel
40
+ ]
41
+ )
42
+ const mergedDefaultModelService = pickFirstNonEmptyString(
43
+ [
44
+ params.userConfig?.defaultModelService,
45
+ params.config?.defaultModelService
46
+ ]
47
+ )
40
48
 
41
49
  const serviceEntries = Object.entries(mergedModelServices)
42
50
  const modelToService = new Map<string, string>()
@@ -54,20 +62,21 @@ const resolveQueryModel = (params: {
54
62
  }
55
63
  }
56
64
 
65
+ if (availableModels.length === 0) return undefined
66
+
57
67
  const resolveDefaultModel = () => {
58
- if (availableModels.length === 0) return undefined
59
68
  if (mergedDefaultModel && modelToService.has(mergedDefaultModel)) return mergedDefaultModel
60
69
  if (mergedDefaultModelService && mergedModelServices[mergedDefaultModelService]) {
61
- const service = mergedModelServices[mergedDefaultModelService]
70
+ const service = mergedModelServices[mergedDefaultModelService] as ModelServiceConfig | undefined
62
71
  const models = Array.isArray(service?.models)
63
- ? service?.models.filter(item => typeof item === 'string' && item.trim() !== '')
72
+ ? service?.models.filter((item: unknown) => typeof item === 'string' && (item as string).trim() !== '')
64
73
  : []
65
74
  if (models.length > 0) return models[0]
66
75
  }
67
76
  return availableModels[0]
68
77
  }
69
78
 
70
- const resolvedModel = inputModel ?? resolveDefaultModel()
79
+ const resolvedModel = resolveDefaultModel()
71
80
  if (!resolvedModel) return undefined
72
81
 
73
82
  const resolvedService = modelToService.get(resolvedModel) ??
package/src/env.ts CHANGED
@@ -11,8 +11,6 @@ export interface ServerEnv {
11
11
  __VF_PROJECT_AI_CLIENT_MODE__?: 'dev' | 'static'
12
12
  __VF_PROJECT_AI_CLIENT_BASE__?: string
13
13
  __VF_PROJECT_AI_CLIENT_DIST_PATH__?: string
14
- __VF_PROJECT_AI_ADAPTER_CLAUDE_CODE_CLI_PATH__?: string
15
- __VF_PROJECT_AI_ADAPTER_CLAUDE_CODE_CLI_ARGS__?: string
16
14
  }
17
15
 
18
16
  export function loadEnv(): ServerEnv {
@@ -26,10 +24,7 @@ export function loadEnv(): ServerEnv {
26
24
  __VF_PROJECT_AI_SERVER_ALLOW_CORS__,
27
25
  __VF_PROJECT_AI_CLIENT_MODE__ = 'static',
28
26
  __VF_PROJECT_AI_CLIENT_BASE__,
29
- __VF_PROJECT_AI_CLIENT_DIST_PATH__,
30
-
31
- __VF_PROJECT_AI_ADAPTER_CLAUDE_CODE_CLI_PATH__,
32
- __VF_PROJECT_AI_ADAPTER_CLAUDE_CODE_CLI_ARGS__
27
+ __VF_PROJECT_AI_CLIENT_DIST_PATH__
33
28
  } = processEnv || {}
34
29
  return {
35
30
  __VF_PROJECT_AI_SERVER_HOST__,
@@ -42,12 +37,8 @@ export function loadEnv(): ServerEnv {
42
37
  __VF_PROJECT_AI_SERVER_ALLOW_CORS__: __VF_PROJECT_AI_SERVER_ALLOW_CORS__ != null
43
38
  ? __VF_PROJECT_AI_SERVER_ALLOW_CORS__ === 'true'
44
39
  : true,
45
- __VF_PROJECT_AI_CLIENT_MODE__:
46
- __VF_PROJECT_AI_CLIENT_MODE__ as ServerEnv['__VF_PROJECT_AI_CLIENT_MODE__'],
40
+ __VF_PROJECT_AI_CLIENT_MODE__: __VF_PROJECT_AI_CLIENT_MODE__ as ServerEnv['__VF_PROJECT_AI_CLIENT_MODE__'],
47
41
  __VF_PROJECT_AI_CLIENT_BASE__,
48
- __VF_PROJECT_AI_CLIENT_DIST_PATH__,
49
-
50
- __VF_PROJECT_AI_ADAPTER_CLAUDE_CODE_CLI_PATH__,
51
- __VF_PROJECT_AI_ADAPTER_CLAUDE_CODE_CLI_ARGS__
42
+ __VF_PROJECT_AI_CLIENT_DIST_PATH__
52
43
  }
53
44
  }
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from './adapter'
2
1
  export * from './config'
3
2
  export * from './controllers/benchmark'
4
3
  export * from './controllers/config'