@tbox.cn/app-template-agent 0.9.0 → 0.10.1
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/AGENTS.md +89 -34
- package/ENV.md +6 -5
- package/README.md +4 -3
- package/apps/client/package.json +2 -2
- package/apps/client/src/app.tsx +1 -1
- package/apps/client/src/business/README.md +3 -3
- package/apps/client/src/cards/registry.ts +1 -1
- package/apps/client/src/main.tsx +1 -1
- package/apps/client/src/modules.ts +3 -3
- package/apps/client/src/pages/index/index.tsx +1 -1
- package/apps/client/src/platform/AgentChatApp.tsx +2 -2
- package/apps/client/src/platform/agent-runtime.ts +2 -2
- package/apps/client/src/store/chat.ts +2 -2
- package/apps/client/vite.config.ts +2 -4
- package/apps/server/package.json +2 -2
- package/apps/server/src/app-tools.ts +1 -1
- package/apps/server/src/app.ts +13 -6
- package/apps/server/src/cli/collect-registry.ts +1 -1
- package/apps/server/src/cli/plugin-doctor.ts +1 -1
- package/apps/server/src/cli/plugin-inspect.ts +1 -1
- package/apps/server/src/config/integration.ts +1 -1
- package/apps/server/src/dev.ts +2 -2
- package/apps/server/src/index.ts +1 -1
- package/apps/server/src/intent-routes.ts +1 -1
- package/apps/server/src/modules.ts +3 -3
- package/apps/server/src/pre-tools.ts +2 -2
- package/apps/server/src/tools/clock.ts +2 -2
- package/apps/server/src/tools/translate.ts +2 -2
- package/apps/server/tests/agent-prompt.test.ts +1 -1
- package/apps/server/tests/cards-registry.test.ts +1 -1
- package/apps/server/tests/intent-dispatcher.test.ts +1 -1
- package/apps/server/tests/tool-runtime.test.ts +1 -1
- package/package.json +3 -3
- package/packages/agent-ui-kit/package.json +2 -2
- package/packages/agent-ui-kit/src/ChatPage.tsx +1 -1
- package/packages/agent-ui-kit/src/chat-config.ts +1 -1
- package/packages/agent-ui-kit/src/components/ActionBar/DebugButton.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ActionBar/index.tsx +2 -2
- package/packages/agent-ui-kit/src/components/CardRenderer.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ChatInput/index.test.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ChatInput/index.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ChatInput/voice/useVoicePress.ts +2 -2
- package/packages/agent-ui-kit/src/components/MessageBubble/index.tsx +1 -1
- package/packages/agent-ui-kit/src/components/QuickCommands/index.test.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.test.ts +1 -1
- package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.ts +1 -1
- package/packages/agent-ui-kit/src/hooks/useMediaUpload.ts +2 -2
- package/packages/agent-ui-kit/src/hooks/useTTSAutoPlay.ts +2 -2
- package/packages/agent-ui-kit/src/index.ts +1 -1
- package/packages/agent-ui-kit/src/store-context.tsx +1 -1
- package/packages/agent-ui-kit/src/types.ts +2 -2
- package/packages/agent-ui-kit/src/utils/haptics.test.ts +1 -1
- package/packages/agent-ui-kit/src/utils/haptics.ts +1 -1
- package/packages/agent-ui-kit/src/utils/tool-call-display.test.ts +1 -1
- package/packages/agent-ui-kit/src/utils/tool-call-display.ts +1 -1
- package/packages/provider-custom/AGENTS.md +47 -21
- package/packages/provider-custom/README.md +1 -1
- package/packages/provider-custom/package.json +3 -2
- package/packages/provider-custom/src/server/index.ts +15 -12
- package/packages/provider-custom/tbox.module.json +8 -8
- package/pnpm-lock.template.yaml +114 -59
- package/pnpm-workspace.template.yaml +8 -4
- package/profiles/mall/TEMPLATE.md +42 -0
- package/profiles/mall.json +3 -3
- package/apps/client/src/shims/node-stub.ts +0 -14
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-sdk
|
|
2
|
-
import { createTool } from '@tbox.cn/app-sdk
|
|
1
|
+
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-agent-sdk-server 的 createTool 入口(单例铁律)
|
|
2
|
+
import { createTool } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { loadAgentPromptConfig } from '@tbox.cn/app-sdk
|
|
2
|
+
import { loadAgentPromptConfig } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// cards 字段运行期声明,registry 仅余 cardType 注册与 dataSchema 校验职责。
|
|
4
4
|
import { describe, it, expect } from 'vitest';
|
|
5
5
|
import { diagnosePlugins } from '@tbox.cn/agent-plugin/doctor';
|
|
6
|
-
import { createServerContext, createPluginIntegration } from '@tbox.cn/app-sdk
|
|
6
|
+
import { createServerContext, createPluginIntegration } from '@tbox.cn/app-agent-sdk-server';
|
|
7
7
|
import { registerAll } from '../src/modules.js';
|
|
8
8
|
|
|
9
9
|
describe('工具 / 卡片 registry 一致性(自注册闭环)', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { createServerContext } from '@tbox.cn/app-sdk
|
|
2
|
+
import { createServerContext } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import type { RequestContext } from '@tbox.cn/app-contracts';
|
|
4
4
|
import { createAppIntentDispatcher } from '../src/intent-routes.js';
|
|
5
5
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
createEngineFromContext,
|
|
6
6
|
createInMemoryMemoryStore,
|
|
7
7
|
resolveMemoryStore,
|
|
8
|
-
} from '@tbox.cn/app-sdk
|
|
8
|
+
} from '@tbox.cn/app-agent-sdk-server';
|
|
9
9
|
import { registerAll } from '../src/modules.js';
|
|
10
10
|
import { translateTool } from '../src/tools/translate.js';
|
|
11
11
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbox.cn/app-template-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "tbox AI Agent 全栈模板(多包 pnpm workspace):apps/client + apps/server。唯一模板(W4 单一模板统一化:缺省空装配 chat 形态;mall 能力经 profiles/mall 加装),能力经 tbox-app module add 模块扩展(shopping-guide/member 等)。",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24.0.0 <25.0.0"
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"LICENSE"
|
|
33
33
|
],
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@tbox.cn/app-sdk": "0.20.0",
|
|
36
35
|
"eslint": "9.39.5",
|
|
37
36
|
"typescript-eslint": "8.67.0",
|
|
38
37
|
"eslint-plugin-react-hooks": "5.2.0",
|
|
39
|
-
"vite": "6.4.3"
|
|
38
|
+
"vite": "6.4.3",
|
|
39
|
+
"@tbox.cn/app-sdk-server": "0.21.0"
|
|
40
40
|
},
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"publishConfig": {
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"LICENSE"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@tbox.cn/app-sdk": "catalog:",
|
|
31
30
|
"@tbox.cn/app-contracts": "catalog:",
|
|
32
31
|
"@phosphor-icons/react": "catalog:",
|
|
33
32
|
"antd-mobile": "catalog:",
|
|
34
33
|
"react-markdown": "catalog:",
|
|
35
34
|
"remark-gfm": "catalog:",
|
|
36
|
-
"zustand": "catalog:"
|
|
35
|
+
"zustand": "catalog:",
|
|
36
|
+
"@tbox.cn/app-agent-sdk-client": "catalog:"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": "catalog:",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - 域自持段(首屏数据/门禁/详情弹层/活动预热)经槽渲染函数自带——本页零域语义。
|
|
8
8
|
*/
|
|
9
9
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
-
import { consumeAutoSendQuery, runAutoSend } from '@tbox.cn/app-sdk
|
|
10
|
+
import { consumeAutoSendQuery, runAutoSend } from '@tbox.cn/app-agent-sdk-client';
|
|
11
11
|
import { usePullDownHistory } from './hooks/use-pull-down-history';
|
|
12
12
|
import type { TboxCardPayload } from '@tbox.cn/app-contracts';
|
|
13
13
|
import { CardRenderer } from './components/CardRenderer';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - HELLO_ACK settings 水合:服务端单一真源(applyServerSettings;五键整组语义,禁部分水合)。
|
|
7
7
|
*/
|
|
8
8
|
import { create } from 'zustand';
|
|
9
|
-
import type { ChatUiSettings } from '@tbox.cn/app-sdk
|
|
9
|
+
import type { ChatUiSettings } from '@tbox.cn/app-agent-sdk-client';
|
|
10
10
|
|
|
11
11
|
export interface QuickCommand {
|
|
12
12
|
/** 纯文案;前导星标/图标由 QuickCommands 组件渲染,不要写进 label */
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useEffect, useState, useSyncExternalStore } from 'react';
|
|
2
|
-
import { createLogger } from '@tbox.cn/app-sdk
|
|
2
|
+
import { createLogger } from '@tbox.cn/app-agent-sdk-client';
|
|
3
3
|
|
|
4
4
|
const ttsActionLogger = createLogger('tts');
|
|
5
5
|
import { Copy, SpeakerHigh, ThumbsDown, ThumbsUp } from '@phosphor-icons/react';
|
|
6
6
|
import { useChatStore } from '../../store-context';
|
|
7
7
|
import { useChatConfigStore } from '../../chat-config';
|
|
8
|
-
import { useFeedbackAdapter, useRefreshSession, useTTSAdapter } from '@tbox.cn/app-sdk
|
|
8
|
+
import { useFeedbackAdapter, useRefreshSession, useTTSAdapter } from '@tbox.cn/app-agent-sdk-client';
|
|
9
9
|
import type { ChatMessage } from '../../types';
|
|
10
10
|
import { copyText } from '../../utils/copyText';
|
|
11
11
|
import { toast } from '../../utils/toast';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - CardRenderer:聊天入口(组合层覆盖注册表 cards);
|
|
7
7
|
* - RawCardRenderer:原始形态(rawCards,无覆盖)——首页详情弹层 body 等防嵌套入口。
|
|
8
8
|
*/
|
|
9
|
-
import { CardRenderer as SdkCardRenderer } from '@tbox.cn/app-sdk
|
|
9
|
+
import { CardRenderer as SdkCardRenderer } from '@tbox.cn/app-agent-sdk-client';
|
|
10
10
|
import type { TboxCardPayload, UiAction } from '@tbox.cn/app-contracts';
|
|
11
11
|
import { useChatCards, useChatRawCards, useChatStore } from '../store-context';
|
|
12
12
|
|
|
@@ -8,7 +8,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
8
8
|
interactionState: 'idle' as VoiceInteractionState,
|
|
9
9
|
}));
|
|
10
10
|
|
|
11
|
-
vi.mock('@tbox.cn/app-sdk
|
|
11
|
+
vi.mock('@tbox.cn/app-agent-sdk-client', () => ({
|
|
12
12
|
isInAlipayShell: () => false,
|
|
13
13
|
useASRAdapter: () => undefined,
|
|
14
14
|
}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useMediaUpload } from '../../hooks/useMediaUpload';
|
|
3
|
-
import { useASRAdapter, isInAlipayShell } from '@tbox.cn/app-sdk
|
|
3
|
+
import { useASRAdapter, isInAlipayShell } from '@tbox.cn/app-agent-sdk-client';
|
|
4
4
|
import { useChatConfigStore } from '../../chat-config';
|
|
5
5
|
|
|
6
6
|
import type { ChatInputMessage, InputMethod } from '../../types';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import type { IASRAdapter } from '@tbox.cn/app-sdk
|
|
3
|
-
import { useRefreshSession } from '@tbox.cn/app-sdk
|
|
2
|
+
import type { IASRAdapter } from '@tbox.cn/app-agent-sdk-client';
|
|
3
|
+
import { useRefreshSession } from '@tbox.cn/app-agent-sdk-client';
|
|
4
4
|
import { isSessionExpiredError } from '../../../utils/session-error';
|
|
5
5
|
import { toast } from '../../../utils/toast';
|
|
6
6
|
import {
|
|
@@ -9,7 +9,7 @@ import ToolCallBlock from '../../components/ToolCallBlock';
|
|
|
9
9
|
import { ActionBar, CopyButton, getMessageCopyText } from '../../components/ActionBar';
|
|
10
10
|
import { DebugButton } from '../../components/ActionBar/DebugButton';
|
|
11
11
|
import { CardRenderer } from '../CardRenderer';
|
|
12
|
-
import { CardCarousel } from '@tbox.cn/app-sdk
|
|
12
|
+
import { CardCarousel } from '@tbox.cn/app-agent-sdk-client';
|
|
13
13
|
import { useChatStore, useInlineCardFilter } from '../../store-context';
|
|
14
14
|
import { copyText } from '../../utils/copyText';
|
|
15
15
|
import { toast } from '../../utils/toast';
|
|
@@ -8,7 +8,7 @@ import { createRoot } from 'react-dom/client';
|
|
|
8
8
|
import { flushSync } from 'react-dom';
|
|
9
9
|
import type { ReactNode } from 'react';
|
|
10
10
|
import { create } from 'zustand';
|
|
11
|
-
import type { CoreChatStore } from '@tbox.cn/app-sdk
|
|
11
|
+
import type { CoreChatStore } from '@tbox.cn/app-agent-sdk-client';
|
|
12
12
|
import { configureChatConfigDefaults, useChatConfigStore } from '../../chat-config';
|
|
13
13
|
import { KitChatProvider } from '../../store-context';
|
|
14
14
|
import { QuickCommands } from './index';
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
PRE_TOOL_CALL_NAME,
|
|
10
10
|
SKILL_TOOL_CALL_NAME,
|
|
11
11
|
} from '@tbox.cn/app-contracts';
|
|
12
|
-
import type { ToolCallInfo } from '@tbox.cn/app-sdk
|
|
12
|
+
import type { ToolCallInfo } from '@tbox.cn/app-agent-sdk-client';
|
|
13
13
|
import {
|
|
14
14
|
buildSummaryText,
|
|
15
15
|
deriveSummary,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* debug 门控在渲染层(组件 debug prop)——视图模型保持纯数据投影,不感知环境。
|
|
6
6
|
*/
|
|
7
7
|
import { describeToolCall } from '../../utils/tool-call-display';
|
|
8
|
-
import type { ToolCallInfo } from '@tbox.cn/app-sdk
|
|
8
|
+
import type { ToolCallInfo } from '@tbox.cn/app-agent-sdk-client';
|
|
9
9
|
import {
|
|
10
10
|
MEMORY_TOOL_CALL_NAME,
|
|
11
11
|
parseMemoryToolCallArgs,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createLogger } from '@tbox.cn/app-sdk
|
|
1
|
+
import { createLogger } from '@tbox.cn/app-agent-sdk-client';
|
|
2
2
|
|
|
3
3
|
const mediaLogger = createLogger('media');
|
|
4
4
|
|
|
5
5
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
6
|
-
import { useUploadAdapter, useRefreshSession, chooseImage, chooseVideo } from '@tbox.cn/app-sdk
|
|
6
|
+
import { useUploadAdapter, useRefreshSession, chooseImage, chooseVideo } from '@tbox.cn/app-agent-sdk-client';
|
|
7
7
|
|
|
8
8
|
import { isSessionExpiredError } from '../utils/session-error';
|
|
9
9
|
import { toast } from '../utils/toast';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
-
import type { CoreChatState } from '@tbox.cn/app-sdk
|
|
2
|
+
import type { CoreChatState } from '@tbox.cn/app-agent-sdk-client';
|
|
3
3
|
import { useChatStoreApi } from '../store-context';
|
|
4
|
-
import { useTTSAdapter } from '@tbox.cn/app-sdk
|
|
4
|
+
import { useTTSAdapter } from '@tbox.cn/app-agent-sdk-client';
|
|
5
5
|
|
|
6
6
|
const FLUSH_MS = 300; // 累积 delta 后批量送,避免过多 WS 消息
|
|
7
7
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @app/agent-ui-kit:Agent 对话壳 UI 组件包(源码发布,单一模板统一化 W2-1)。
|
|
3
3
|
*
|
|
4
4
|
* 消费面:应用经 `<ChatPage store cards slots .../>` 单点装配(或自组 KitChatProvider 树);
|
|
5
|
-
* 域模块(如 mall-
|
|
5
|
+
* 域模块(如 mall-core)经 home 槽渲染函数自持域 UI——kit 组件零域语义。
|
|
6
6
|
* 主题:`@app/agent-ui-kit/theme`(applyTheme)+ `theme/index.less`(配合纯 CSS 主题包级联)。
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { createContext, useContext, useMemo, type ReactNode } from 'react';
|
|
12
12
|
import type { CardComponent, TboxCardPayload } from '@tbox.cn/app-contracts';
|
|
13
|
-
import type { ClientSlotRegistry, CoreChatState, CoreChatStore } from '@tbox.cn/app-sdk
|
|
13
|
+
import type { ClientSlotRegistry, CoreChatState, CoreChatStore } from '@tbox.cn/app-agent-sdk-client';
|
|
14
14
|
|
|
15
15
|
export interface KitChatContextValue {
|
|
16
16
|
/** 应用注入的 chat store(zustand 绑定 hook + API) */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** 媒体 / 消息类型(协议类型已下沉 @tbox.cn/app-sdk
|
|
1
|
+
/** 媒体 / 消息类型(协议类型已下沉 @tbox.cn/app-agent-sdk-client,此处 re-export 保持单一来源) */
|
|
2
2
|
export type {
|
|
3
3
|
MediaType,
|
|
4
4
|
InputMethod,
|
|
@@ -8,7 +8,7 @@ export type {
|
|
|
8
8
|
MessageStatus,
|
|
9
9
|
ToolCallInfo,
|
|
10
10
|
ChatMessage,
|
|
11
|
-
} from '@tbox.cn/app-sdk
|
|
11
|
+
} from '@tbox.cn/app-agent-sdk-client';
|
|
12
12
|
|
|
13
13
|
/** 单种媒体的上传约束(对齐原模板 FileTypeConfig,UI 层约定,留在模板) */
|
|
14
14
|
export interface FileTypeConfig {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
5
|
|
|
6
6
|
const mocks = vi.hoisted(() => ({ callJsapi: vi.fn() }));
|
|
7
|
-
vi.mock('@tbox.cn/app-sdk
|
|
7
|
+
vi.mock('@tbox.cn/app-agent-sdk-client', () => ({ callJsapi: mocks.callJsapi }));
|
|
8
8
|
|
|
9
9
|
import { hapticTap, resetHapticBridgeState } from './haptics';
|
|
10
10
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 注意 iOS 上无论哪条路径都可能无感——Safari 不开放 Taptic Engine 给网页,
|
|
9
9
|
* 容器内是否有感取决于宿主 App 的实现。调用方不应依赖它的成功与否。
|
|
10
10
|
*/
|
|
11
|
-
import { callJsapi } from '@tbox.cn/app-sdk
|
|
11
|
+
import { callJsapi } from '@tbox.cn/app-agent-sdk-client';
|
|
12
12
|
|
|
13
13
|
/** 极短时长(ms):轻点级别,不是提示级别的长震。 */
|
|
14
14
|
const TAP_DURATION_MS = 10;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { describeToolCall, formatCompactToolIo } from './tool-call-display';
|
|
3
|
-
import type { ToolCallInfo } from '@tbox.cn/app-sdk
|
|
3
|
+
import type { ToolCallInfo } from '@tbox.cn/app-agent-sdk-client';
|
|
4
4
|
import { buildPreToolArgsPayload, buildPreToolResultPayload } from '@tbox.cn/app-contracts';
|
|
5
5
|
import {
|
|
6
6
|
buildMemoryToolCallPayload,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
parsePreToolToolCallResult,
|
|
17
17
|
parseSkillToolCallArgs,
|
|
18
18
|
} from '@tbox.cn/app-contracts';
|
|
19
|
-
import type { ToolCallInfo } from '@tbox.cn/app-sdk
|
|
19
|
+
import type { ToolCallInfo } from '@tbox.cn/app-agent-sdk-client';
|
|
20
20
|
|
|
21
21
|
export type ToolCallDisplay =
|
|
22
22
|
| { kind: 'skill'; label: string; hasDetail: false }
|
|
@@ -1,33 +1,59 @@
|
|
|
1
1
|
# provider-custom —— 自定义 API 实施落点(AI 集成指引)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
本包是**自定义 API(内联声明)的 adapter 代码落点**:某服务槽在 `config/integrations.json`
|
|
4
|
+
保存内联声明(provider 为对象 + implementation 字面量)而 adapter 未实施时,服务调用报
|
|
5
|
+
`PROVIDER_NOT_IMPLEMENTED`——由 AI 助手按本指引在本包实施,注册命中后即恢复。声明写法与
|
|
6
|
+
维度选择见应用根 `AGENTS.md`「自定义服务集成」。
|
|
6
7
|
|
|
7
8
|
## 实施三步
|
|
8
9
|
|
|
9
|
-
1. **读声明**:`config/integrations.json` 中目标服务(如 `parking.query`)的
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
2. **实现 adapter**:在 `src/server/` 新建实现文件,实现该服务对应模块的 Port
|
|
13
|
-
|
|
14
|
-
`
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
|
|
10
|
+
1. **读声明**:`config/integrations.json` 中目标服务(如 `parking.query`)的 `provider`
|
|
11
|
+
为对象(`{ provider, credentialType, configSchema? }`)+ `implementation` 字面量——这是
|
|
12
|
+
厂商身份与凭据约定。
|
|
13
|
+
2. **实现 adapter**:在 `src/server/` 新建实现文件,实现该服务对应模块的 Port 接口(接口
|
|
14
|
+
定义见消费模块 `src/server/ports.ts`(或 `ports/` 目录)或 `@app/contracts-mall`
|
|
15
|
+
契约包——本包按需加 `@app/contracts-mall` 依赖并 `import type`)。HTTP 调用一律经
|
|
16
|
+
`input.transport`(baseUrl 取自绑定 config;熔断/HTTPS 强制(localhost 的 http 豁免)/
|
|
17
|
+
响应体 1MB 上限内建):
|
|
18
|
+
`await input.transport.request({ path, method, body, query })`。
|
|
20
19
|
3. **注册**:在 `src/server/index.ts` 的 `register(ctx)` 中调用
|
|
21
|
-
`ctx.integrations?.registerAdapter('<provider 名>', '
|
|
22
|
-
|
|
20
|
+
`ctx.integrations?.registerAdapter('<provider 名>', 'inline', factory)`——**注册键
|
|
21
|
+
implementation 段恒为 `'inline'`**(内联声明运行时按合成 `'inline'` 寻址,与声明中的
|
|
22
|
+
implementation 字面量无关)。
|
|
23
|
+
|
|
24
|
+
**多服务单键**:同一 provider 名的全部服务共享唯一注册键——重复注册后者覆盖前者。同一
|
|
25
|
+
后端接多个服务 = 只注册一次,factory 内按 `input.service` 分支返回各 Port 实现;或每服务
|
|
26
|
+
用不同 provider 名分键。adapter 内取凭据值(如自签名):`input.credential()` 惰性 getter
|
|
27
|
+
(返回 `{ scope, type, value }`;未配 credentialRef → undefined)。
|
|
28
|
+
|
|
29
|
+
## 认证与凭据
|
|
30
|
+
|
|
31
|
+
| 认证形态 | credentialType(声明与凭据文件一致) | 机制 |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| 静态头(x-api-key 等白名单头名) | `static-headers-v1`(SDK 内置) | 头自动注入,adapter 全部经 `input.transport` |
|
|
34
|
+
| 其他(Bearer / 自定义签名…) | 自定(如 `bearer-v1`) | 本包 `register(ctx)` 先 `ctx.authStrategies.register({ credentialType, apply(input) {...} })` 注册策略(SDK `ProviderAuthStrategy`),adapter 同走 `input.transport` |
|
|
35
|
+
|
|
36
|
+
- **勿用 `'-'`**:非 local 供给在 transport 构造期抛「未知认证类型」。
|
|
37
|
+
- 静态头白名单(本应用 `apps/server/src/app.ts`):`content-type` / `sign` / `timestamp` /
|
|
38
|
+
`publickey` / `x-api-key`;白名单外头名走自定义策略。
|
|
39
|
+
- 凭据文件(**嵌套形**,运行时读取格式)`config/credentials/<stem>.json`:
|
|
40
|
+
`{ "type": "<credentialType>", "value": { "<头名/参数名>": "<真值>" } }`(省略 `scope` =
|
|
41
|
+
全域通配)。声明/实例持 `credentialRef: "secret://<stem>"`;服务级 stem =
|
|
42
|
+
`${provider}-${service}`,共享 stem = `${provider}-global`(按实例差异化凭据另有
|
|
43
|
+
`${provider}-${instanceId}-${domain}` 形)。真值只进凭据文件或平台
|
|
44
|
+
env——不进 integrations.json、代码与 prompt。
|
|
45
|
+
- 槽 `instances` 省略 = 通配激活(**勿写空对象 `{}`** = 零激活);已绑字符串厂商的槽整组
|
|
46
|
+
替换前先向用户确认。
|
|
23
47
|
|
|
24
48
|
## 完成判据
|
|
25
49
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
50
|
+
- `pnpm typecheck && pnpm build` 通过;
|
|
51
|
+
- 平台重启后该服务的调用不再报 `PROVIDER_NOT_IMPLEMENTED`(resolveService 惰性——调用时
|
|
52
|
+
观测;通配槽下 doctor 不检查凭据,运行时为最终裁判)。
|
|
28
53
|
|
|
29
54
|
## 真实厂商接入
|
|
30
55
|
|
|
31
|
-
对外提供正式 API 的厂商(支付/会员等大规模集成)走官方 provider 包形态:
|
|
32
|
-
|
|
33
|
-
`
|
|
56
|
+
对外提供正式 API 的厂商(支付/会员等大规模集成)走官方 provider 包形态:manifest
|
|
57
|
+
`declare.providers.slots` 声明供给 + 独立包发布 + `tbox-app module add` 装配 +
|
|
58
|
+
`tbox-app provider bind` 绑定。样例:`tbox-app module add @tbox.cn/app-provider-mock --mode
|
|
59
|
+
codegen --source @tbox.cn/app-provider-mock` 后参照 `packages/provider-mock` 结构。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @tbox.cn/app-provider-custom
|
|
2
2
|
|
|
3
|
-
自定义厂商实施落点空包(与 provider-mock 并列的中立空壳):manifest contributes 全空(零贡献
|
|
3
|
+
自定义厂商实施落点空包(与 provider-mock / provider-mocktest 并列的中立空壳):manifest contributes 全空(零贡献
|
|
4
4
|
合法——descriptor zod 全 default),出厂无任何供给/需求/卡片声明,纯为 AI 实施自定义 API
|
|
5
5
|
adapter 提供**有形代码落点**。闭环机制见 AGENTS.md(SDK 零改动——registerAdapter 命中即转 ok)。
|
|
6
6
|
|
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
"prepack": "pnpm build"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@tbox.cn/app-
|
|
25
|
-
"@tbox.cn/app-
|
|
24
|
+
"@tbox.cn/app-contracts": "catalog:",
|
|
25
|
+
"@tbox.cn/app-agent-sdk-client": "catalog:",
|
|
26
|
+
"@tbox.cn/app-agent-sdk-server": "catalog:"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@types/node": "24.13.3",
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 自定义厂商实施落点空包·服务端入口(单包多厂商——多个自定义 API 的
|
|
3
3
|
* adapter 均在此包 register,注册表双键不关心包边界)。
|
|
4
4
|
*
|
|
5
5
|
* 零贡献合法(manifest contributes 全空——descriptor zod 全 default):本包出厂无任何
|
|
6
|
-
* 供给/需求/卡片声明,纯为 AI
|
|
7
|
-
* 1.
|
|
8
|
-
* 2.
|
|
9
|
-
* 3. AI
|
|
10
|
-
* registerAdapter(provider,
|
|
11
|
-
* 4.
|
|
6
|
+
* 供给/需求/卡片声明,纯为 AI 实施自定义 API adapter 提供**有形代码落点**。运行时闭环:
|
|
7
|
+
* 1. 某服务槽保存自定义 API 内联声明(integrations.json:provider 对象 + implementation 字面量);
|
|
8
|
+
* 2. 服务调用解析该绑定 → adapter 未注册 → PROVIDER_NOT_IMPLEMENTED(fail-visible);
|
|
9
|
+
* 3. AI 按本包 AGENTS.md 指引实现 adapter 并在 register 挂载
|
|
10
|
+
* ctx.integrations?.registerAdapter(provider, 'inline', factory);
|
|
11
|
+
* 4. 平台重启后 register 命中 → 该服务调用恢复正常(完成信号)。
|
|
12
12
|
*
|
|
13
13
|
* 真实厂商接入(官方 provider 包形态:manifest 槽声明 + 独立包发布)跳转见 AGENTS.md。
|
|
14
14
|
*/
|
|
15
|
-
import type { ServerContext, ServerModule } from '@tbox.cn/app-sdk
|
|
15
|
+
import type { ServerContext, ServerModule } from '@tbox.cn/app-agent-sdk-server';
|
|
16
16
|
|
|
17
17
|
export const PROVIDER_CUSTOM = 'provider-custom';
|
|
18
18
|
|
|
@@ -20,13 +20,16 @@ export const PROVIDER_CUSTOM = 'provider-custom';
|
|
|
20
20
|
* adapter 工厂签名示例(真实实施时替换本注释为具体 adapter 注册):
|
|
21
21
|
*
|
|
22
22
|
* const myApiAdapterFactory: ServiceAdapterFactory = (input) => {
|
|
23
|
-
* // input.service 服务 id(如 'parking.query')
|
|
23
|
+
* // input.service 服务 id(如 'parking.query'——多服务单键时按此分支返回各 Port)
|
|
24
24
|
* // input.instanceId 部署实例键(mall 场景 = mallId;通配激活时由框架解析)
|
|
25
|
-
* // input.config
|
|
26
|
-
* //
|
|
25
|
+
* // input.config 绑定组五层合并后的连接参数(baseUrl 等)
|
|
26
|
+
* // input.transport HTTP 通道(baseUrl/认证/熔断/HTTPS 强制内建):
|
|
27
|
+
* // await input.transport.request({ path, method, body, query })
|
|
28
|
+
* // input.credential?.() 惰性凭据 getter(返回 { scope, type, value };未配 → undefined)
|
|
27
29
|
* return new MyApiServiceImpl(input);
|
|
28
30
|
* };
|
|
29
|
-
*
|
|
31
|
+
* // 注册键 implementation 段恒为 'inline'(内联声明运行时按合成 'inline' 寻址):
|
|
32
|
+
* ctx.integrations?.registerAdapter('my-custom-api', 'inline', myApiAdapterFactory);
|
|
30
33
|
*/
|
|
31
34
|
export function register(ctx: ServerContext): void {
|
|
32
35
|
// 挂点:多个自定义 API 的 adapter 均在此注册(见上方签名示例)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"
|
|
3
|
+
"id": "provider-custom",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"kind": "business",
|
|
6
6
|
"risk": {
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
"distribution": {
|
|
11
11
|
"defaultMode": "codegen"
|
|
12
12
|
},
|
|
13
|
-
"
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"modules": []
|
|
15
|
+
},
|
|
16
|
+
"env": [],
|
|
17
|
+
"declare": {
|
|
14
18
|
"handlers": [],
|
|
15
19
|
"tools": [],
|
|
16
20
|
"cards": [],
|
|
@@ -20,10 +24,6 @@
|
|
|
20
24
|
"providers": {
|
|
21
25
|
"slots": []
|
|
22
26
|
},
|
|
23
|
-
"
|
|
24
|
-
}
|
|
25
|
-
"dependencies": {
|
|
26
|
-
"modules": []
|
|
27
|
-
},
|
|
28
|
-
"env": []
|
|
27
|
+
"consumes": []
|
|
28
|
+
}
|
|
29
29
|
}
|