@zhin.js/core 1.3.1 → 1.3.3
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/README.md +66 -11
- package/lib/adapter.d.ts +41 -3
- package/lib/adapter.js +110 -6
- package/lib/agent-prompt.d.ts +0 -1
- package/lib/agent-prompt.js +0 -1
- package/lib/built/adapter-process.d.ts +11 -2
- package/lib/built/adapter-process.js +43 -2
- package/lib/built/agent-preset.d.ts +0 -1
- package/lib/built/agent-preset.js +0 -1
- package/lib/built/ai-access.d.ts +36 -0
- package/lib/built/ai-access.js +46 -0
- package/lib/built/ai-outbound/adapter-access.d.ts +3 -0
- package/lib/built/ai-outbound/adapter-access.js +9 -0
- package/lib/built/ai-outbound/extensions/onebot-keyboard.d.ts +2 -0
- package/lib/built/ai-outbound/extensions/onebot-keyboard.js +67 -0
- package/lib/built/ai-outbound/extensions/qq-message.d.ts +3 -0
- package/lib/built/ai-outbound/extensions/qq-message.js +23 -0
- package/lib/built/ai-outbound/index.d.ts +9 -0
- package/lib/built/ai-outbound/index.js +9 -0
- package/lib/built/ai-outbound/parse.d.ts +13 -0
- package/lib/built/ai-outbound/parse.js +94 -0
- package/lib/built/ai-outbound/plain-mention-rewrite.d.ts +6 -0
- package/lib/built/ai-outbound/plain-mention-rewrite.js +37 -0
- package/lib/built/ai-outbound/prompt.d.ts +11 -0
- package/lib/built/ai-outbound/prompt.js +44 -0
- package/lib/built/ai-outbound/resolve.d.ts +4 -0
- package/lib/built/ai-outbound/resolve.js +64 -0
- package/lib/built/ai-outbound/structured-detect.d.ts +3 -0
- package/lib/built/ai-outbound/structured-detect.js +7 -0
- package/lib/built/ai-outbound/types.d.ts +60 -0
- package/lib/built/ai-outbound/types.js +5 -0
- package/lib/built/ai-trigger.d.ts +5 -1
- package/lib/built/ai-trigger.js +3 -7
- package/lib/built/authorization.d.ts +0 -1
- package/lib/built/authorization.js +0 -1
- package/lib/built/command.d.ts +2 -1
- package/lib/built/command.js +14 -4
- package/lib/built/common-adapter-tools.d.ts +25 -26
- package/lib/built/common-adapter-tools.js +48 -49
- package/lib/built/component.d.ts +0 -1
- package/lib/built/component.js +1 -3
- package/lib/built/config.d.ts +4 -1
- package/lib/built/config.js +26 -5
- package/lib/built/connect-endpoint-instance.d.ts +0 -1
- package/lib/built/connect-endpoint-instance.js +3 -2
- package/lib/built/database.d.ts +0 -1
- package/lib/built/database.js +1 -3
- package/lib/built/dispatcher.d.ts +6 -6
- package/lib/built/dispatcher.js +20 -8
- package/lib/built/endpoint-commands.d.ts +3 -0
- package/lib/built/endpoint-commands.js +99 -0
- package/lib/built/endpoint-lifecycle-service.d.ts +28 -0
- package/lib/built/endpoint-lifecycle-service.js +241 -0
- package/lib/built/endpoint-lifecycle.d.ts +0 -1
- package/lib/built/endpoint-lifecycle.js +0 -1
- package/lib/built/endpoint-manager.d.ts +34 -0
- package/lib/built/endpoint-manager.js +1 -0
- package/lib/built/generated-qrcode.d.ts +24 -0
- package/lib/built/generated-qrcode.js +45 -0
- package/lib/built/generic-segment-mapper.d.ts +6 -0
- package/lib/built/generic-segment-mapper.js +232 -0
- package/lib/built/html-renderer-loader.d.ts +13 -0
- package/lib/built/html-renderer-loader.js +33 -0
- package/lib/built/html-segment-fallback.d.ts +2 -2
- package/lib/built/html-segment-fallback.js +0 -1
- package/lib/built/html-to-text.d.ts +0 -1
- package/lib/built/html-to-text.js +0 -1
- package/lib/built/inbound-pipeline.d.ts +0 -1
- package/lib/built/inbound-pipeline.js +0 -1
- package/lib/built/inbound-runner.d.ts +0 -1
- package/lib/built/inbound-runner.js +0 -1
- package/lib/built/interactive-segment-contract.d.ts +6 -0
- package/lib/built/interactive-segment-contract.js +9 -0
- package/lib/built/interactive-segments/action.d.ts +17 -0
- package/lib/built/interactive-segments/action.js +54 -0
- package/lib/built/interactive-segments/button-spec.d.ts +10 -0
- package/lib/built/interactive-segments/button-spec.js +21 -0
- package/lib/built/interactive-segments/handlers.d.ts +9 -0
- package/lib/built/interactive-segments/handlers.js +58 -0
- package/lib/built/interactive-segments/index.d.ts +7 -0
- package/lib/built/interactive-segments/index.js +7 -0
- package/lib/built/interactive-segments/keyboard-segment.d.ts +12 -0
- package/lib/built/interactive-segments/keyboard-segment.js +13 -0
- package/lib/built/interactive-segments/onebot-keyboard.d.ts +10 -0
- package/lib/built/interactive-segments/onebot-keyboard.js +53 -0
- package/lib/built/interactive-segments/resolve.d.ts +9 -0
- package/lib/built/interactive-segments/resolve.js +84 -0
- package/lib/built/interactive-segments/types.d.ts +62 -0
- package/lib/built/interactive-segments/types.js +13 -0
- package/lib/built/introspection-format.d.ts +10 -0
- package/lib/built/introspection-format.js +28 -0
- package/lib/built/login-assist.d.ts +1 -2
- package/lib/built/login-assist.js +0 -1
- package/lib/built/management-command-guard.d.ts +15 -0
- package/lib/built/management-command-guard.js +25 -0
- package/lib/built/message-enrich.d.ts +0 -1
- package/lib/built/message-enrich.js +0 -1
- package/lib/built/message-filter.d.ts +0 -1
- package/lib/built/message-filter.js +1 -3
- package/lib/built/optional-peer-import.d.ts +3 -0
- package/lib/built/optional-peer-import.js +33 -0
- package/lib/built/outbound-media-contract.d.ts +22 -0
- package/lib/built/outbound-media-contract.js +10 -0
- package/lib/built/outbound-media-utils.d.ts +9 -0
- package/lib/built/outbound-media-utils.js +62 -0
- package/lib/built/permission.d.ts +0 -1
- package/lib/built/permission.js +1 -3
- package/lib/built/permit-check.d.ts +0 -1
- package/lib/built/permit-check.js +0 -1
- package/lib/built/permit-parse.d.ts +0 -1
- package/lib/built/permit-parse.js +0 -1
- package/lib/built/platform-permit.d.ts +5 -6
- package/lib/built/platform-permit.js +11 -12
- package/lib/built/prepend-quote-context.d.ts +0 -1
- package/lib/built/prepend-quote-context.js +0 -1
- package/lib/built/qrcode-segment.d.ts +18 -0
- package/lib/built/qrcode-segment.js +78 -0
- package/lib/built/queue-im-field-contract.d.ts +6 -1
- package/lib/built/queue-im-field-contract.js +10 -1
- package/lib/built/rich-segments/adapter-policies.d.ts +9 -0
- package/lib/built/rich-segments/adapter-policies.js +27 -0
- package/lib/built/rich-segments/base.d.ts +11 -0
- package/lib/built/rich-segments/base.js +24 -0
- package/lib/built/rich-segments/builtins.d.ts +4 -0
- package/lib/built/rich-segments/builtins.js +40 -0
- package/lib/built/rich-segments/capabilities.d.ts +6 -0
- package/lib/built/rich-segments/capabilities.js +39 -0
- package/lib/built/rich-segments/html-segment.d.ts +15 -0
- package/lib/built/rich-segments/html-segment.js +65 -0
- package/lib/built/rich-segments/index.d.ts +13 -0
- package/lib/built/rich-segments/index.js +13 -0
- package/lib/built/rich-segments/markdown-segment.d.ts +14 -0
- package/lib/built/rich-segments/markdown-segment.js +61 -0
- package/lib/built/rich-segments/markdown-to-text.d.ts +3 -0
- package/lib/built/rich-segments/markdown-to-text.js +27 -0
- package/lib/built/rich-segments/qrcode-segment.d.ts +18 -0
- package/lib/built/rich-segments/qrcode-segment.js +73 -0
- package/lib/built/rich-segments/registry.d.ts +16 -0
- package/lib/built/rich-segments/registry.js +52 -0
- package/lib/built/rich-segments/resolve.d.ts +5 -0
- package/lib/built/rich-segments/resolve.js +87 -0
- package/lib/built/rich-segments/tts-segment.d.ts +13 -0
- package/lib/built/rich-segments/tts-segment.js +51 -0
- package/lib/built/rich-segments/types.d.ts +84 -0
- package/lib/built/rich-segments/types.js +17 -0
- package/lib/built/roles.d.ts +0 -1
- package/lib/built/roles.js +0 -1
- package/lib/built/runtime-io.d.ts +0 -1
- package/lib/built/runtime-io.js +0 -1
- package/lib/built/schedule.d.ts +55 -0
- package/lib/built/schedule.js +112 -0
- package/lib/built/schema-endpoint-manager.d.ts +17 -0
- package/lib/built/schema-endpoint-manager.js +73 -0
- package/lib/built/schema-feature.d.ts +0 -1
- package/lib/built/schema-feature.js +1 -3
- package/lib/built/segment-contract/assert.d.ts +4 -0
- package/lib/built/segment-contract/assert.js +30 -0
- package/lib/built/segment-contract/delivery.d.ts +5 -0
- package/lib/built/segment-contract/delivery.js +40 -0
- package/lib/built/segment-contract/image.d.ts +5 -0
- package/lib/built/segment-contract/image.js +10 -0
- package/lib/built/segment-contract/index.d.ts +8 -0
- package/lib/built/segment-contract/index.js +7 -0
- package/lib/built/segment-contract/media.d.ts +8 -0
- package/lib/built/segment-contract/media.js +39 -0
- package/lib/built/segment-contract/mention.d.ts +10 -0
- package/lib/built/segment-contract/mention.js +26 -0
- package/lib/built/segment-contract/preview.d.ts +3 -0
- package/lib/built/segment-contract/preview.js +159 -0
- package/lib/built/segment-contract/types.d.ts +70 -0
- package/lib/built/segment-contract/types.js +5 -0
- package/lib/built/segment-contract/validate.d.ts +138 -0
- package/lib/built/segment-contract/validate.js +124 -0
- package/lib/built/skill.d.ts +0 -1
- package/lib/built/skill.js +0 -1
- package/lib/built/speech-loader.d.ts +14 -0
- package/lib/built/speech-loader.js +32 -0
- package/lib/built/tool.d.ts +0 -1
- package/lib/built/tool.js +1 -3
- package/lib/command.d.ts +12 -7
- package/lib/command.js +38 -16
- package/lib/component.d.ts +0 -1
- package/lib/component.js +0 -1
- package/lib/endpoint-capabilities.d.ts +3 -1
- package/lib/endpoint-capabilities.js +0 -1
- package/lib/endpoint.d.ts +0 -1
- package/lib/endpoint.js +0 -1
- package/lib/errors.d.ts +0 -1
- package/lib/errors.js +0 -1
- package/lib/host-plugin-registry.d.ts +0 -1
- package/lib/host-plugin-registry.js +0 -1
- package/lib/im-scene.d.ts +29 -0
- package/lib/im-scene.js +77 -0
- package/lib/im-session-id.d.ts +25 -12
- package/lib/im-session-id.js +35 -17
- package/lib/index.d.ts +25 -5
- package/lib/index.js +22 -4
- package/lib/jsx-dev-runtime.d.ts +0 -1
- package/lib/jsx-dev-runtime.js +0 -1
- package/lib/jsx-runtime.d.ts +0 -1
- package/lib/jsx-runtime.js +0 -1
- package/lib/jsx.d.ts +0 -1
- package/lib/jsx.js +0 -1
- package/lib/message-quote.d.ts +1 -2
- package/lib/message-quote.js +2 -3
- package/lib/message.d.ts +12 -2
- package/lib/message.js +16 -1
- package/lib/models/system-log.d.ts +0 -1
- package/lib/models/system-log.js +0 -1
- package/lib/models/user.d.ts +0 -1
- package/lib/models/user.js +0 -1
- package/lib/notice.d.ts +0 -1
- package/lib/notice.js +0 -1
- package/lib/plugin-context.d.ts +0 -1
- package/lib/plugin-context.js +0 -1
- package/lib/plugin.d.ts +11 -2
- package/lib/plugin.js +22 -23
- package/lib/prompt.d.ts +0 -1
- package/lib/prompt.js +1 -2
- package/lib/request.d.ts +0 -1
- package/lib/request.js +0 -1
- package/lib/tool-zod.d.ts +0 -1
- package/lib/tool-zod.js +0 -1
- package/lib/types-generator.d.ts +0 -1
- package/lib/types-generator.js +0 -1
- package/lib/types.d.ts +30 -11
- package/lib/types.js +0 -1
- package/lib/utils.d.ts +57 -12
- package/lib/utils.js +54 -19
- package/package.json +18 -9
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js.map +0 -1
- package/lib/agent-prompt.d.ts.map +0 -1
- package/lib/agent-prompt.js.map +0 -1
- package/lib/built/adapter-process.d.ts.map +0 -1
- package/lib/built/adapter-process.js.map +0 -1
- package/lib/built/agent-preset.d.ts.map +0 -1
- package/lib/built/agent-preset.js.map +0 -1
- package/lib/built/ai-trigger.d.ts.map +0 -1
- package/lib/built/ai-trigger.js.map +0 -1
- package/lib/built/authorization.d.ts.map +0 -1
- package/lib/built/authorization.js.map +0 -1
- package/lib/built/command.d.ts.map +0 -1
- package/lib/built/command.js.map +0 -1
- package/lib/built/common-adapter-tools.d.ts.map +0 -1
- package/lib/built/common-adapter-tools.js.map +0 -1
- package/lib/built/component.d.ts.map +0 -1
- package/lib/built/component.js.map +0 -1
- package/lib/built/config.d.ts.map +0 -1
- package/lib/built/config.js.map +0 -1
- package/lib/built/connect-endpoint-instance.d.ts.map +0 -1
- package/lib/built/connect-endpoint-instance.js.map +0 -1
- package/lib/built/cron.d.ts +0 -75
- package/lib/built/cron.d.ts.map +0 -1
- package/lib/built/cron.js +0 -122
- package/lib/built/cron.js.map +0 -1
- package/lib/built/database.d.ts.map +0 -1
- package/lib/built/database.js.map +0 -1
- package/lib/built/dispatcher.d.ts.map +0 -1
- package/lib/built/dispatcher.js.map +0 -1
- package/lib/built/endpoint-lifecycle.d.ts.map +0 -1
- package/lib/built/endpoint-lifecycle.js.map +0 -1
- package/lib/built/html-segment-fallback.d.ts.map +0 -1
- package/lib/built/html-segment-fallback.js.map +0 -1
- package/lib/built/html-to-text.d.ts.map +0 -1
- package/lib/built/html-to-text.js.map +0 -1
- package/lib/built/inbound-pipeline.d.ts.map +0 -1
- package/lib/built/inbound-pipeline.js.map +0 -1
- package/lib/built/inbound-runner.d.ts.map +0 -1
- package/lib/built/inbound-runner.js.map +0 -1
- package/lib/built/login-assist.d.ts.map +0 -1
- package/lib/built/login-assist.js.map +0 -1
- package/lib/built/mcp-mesh-registrar.d.ts +0 -9
- package/lib/built/mcp-mesh-registrar.d.ts.map +0 -1
- package/lib/built/mcp-mesh-registrar.js +0 -17
- package/lib/built/mcp-mesh-registrar.js.map +0 -1
- package/lib/built/message-enrich.d.ts.map +0 -1
- package/lib/built/message-enrich.js.map +0 -1
- package/lib/built/message-filter.d.ts.map +0 -1
- package/lib/built/message-filter.js.map +0 -1
- package/lib/built/permission.d.ts.map +0 -1
- package/lib/built/permission.js.map +0 -1
- package/lib/built/permit-check.d.ts.map +0 -1
- package/lib/built/permit-check.js.map +0 -1
- package/lib/built/permit-parse.d.ts.map +0 -1
- package/lib/built/permit-parse.js.map +0 -1
- package/lib/built/platform-permit.d.ts.map +0 -1
- package/lib/built/platform-permit.js.map +0 -1
- package/lib/built/prepend-quote-context.d.ts.map +0 -1
- package/lib/built/prepend-quote-context.js.map +0 -1
- package/lib/built/queue-im-field-contract.d.ts.map +0 -1
- package/lib/built/queue-im-field-contract.js.map +0 -1
- package/lib/built/roles.d.ts.map +0 -1
- package/lib/built/roles.js.map +0 -1
- package/lib/built/runtime-io.d.ts.map +0 -1
- package/lib/built/runtime-io.js.map +0 -1
- package/lib/built/schema-feature.d.ts.map +0 -1
- package/lib/built/schema-feature.js.map +0 -1
- package/lib/built/skill.d.ts.map +0 -1
- package/lib/built/skill.js.map +0 -1
- package/lib/built/tool.d.ts.map +0 -1
- package/lib/built/tool.js.map +0 -1
- package/lib/command.d.ts.map +0 -1
- package/lib/command.js.map +0 -1
- package/lib/component.d.ts.map +0 -1
- package/lib/component.js.map +0 -1
- package/lib/endpoint-capabilities.d.ts.map +0 -1
- package/lib/endpoint-capabilities.js.map +0 -1
- package/lib/endpoint.d.ts.map +0 -1
- package/lib/endpoint.js.map +0 -1
- package/lib/errors.d.ts.map +0 -1
- package/lib/errors.js.map +0 -1
- package/lib/host-plugin-registry.d.ts.map +0 -1
- package/lib/host-plugin-registry.js.map +0 -1
- package/lib/im-session-id.d.ts.map +0 -1
- package/lib/im-session-id.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/jsx-dev-runtime.d.ts.map +0 -1
- package/lib/jsx-dev-runtime.js.map +0 -1
- package/lib/jsx-runtime.d.ts.map +0 -1
- package/lib/jsx-runtime.js.map +0 -1
- package/lib/jsx.d.ts.map +0 -1
- package/lib/jsx.js.map +0 -1
- package/lib/message-quote.d.ts.map +0 -1
- package/lib/message-quote.js.map +0 -1
- package/lib/message.d.ts.map +0 -1
- package/lib/message.js.map +0 -1
- package/lib/models/system-log.d.ts.map +0 -1
- package/lib/models/system-log.js.map +0 -1
- package/lib/models/user.d.ts.map +0 -1
- package/lib/models/user.js.map +0 -1
- package/lib/notice.d.ts.map +0 -1
- package/lib/notice.js.map +0 -1
- package/lib/plugin-context.d.ts.map +0 -1
- package/lib/plugin-context.js.map +0 -1
- package/lib/plugin.d.ts.map +0 -1
- package/lib/plugin.js.map +0 -1
- package/lib/prompt.d.ts.map +0 -1
- package/lib/prompt.js.map +0 -1
- package/lib/request.d.ts.map +0 -1
- package/lib/request.js.map +0 -1
- package/lib/scheduler/scheduler.d.ts +0 -49
- package/lib/scheduler/scheduler.d.ts.map +0 -1
- package/lib/scheduler/scheduler.js +0 -352
- package/lib/scheduler/scheduler.js.map +0 -1
- package/lib/scheduler/types.d.ts +0 -71
- package/lib/scheduler/types.d.ts.map +0 -1
- package/lib/scheduler/types.js +0 -8
- package/lib/scheduler/types.js.map +0 -1
- package/lib/tool-zod.d.ts.map +0 -1
- package/lib/tool-zod.js.map +0 -1
- package/lib/types-generator.d.ts.map +0 -1
- package/lib/types-generator.js.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js.map +0 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { segment } from '../../utils.js';
|
|
2
|
+
import { htmlToFallbackText } from '../html-to-text.js';
|
|
3
|
+
import { RichSegment } from './base.js';
|
|
4
|
+
import { RICH_SEGMENT_MODE } from './types.js';
|
|
5
|
+
async function resolveHtmlRenderer(ctx) {
|
|
6
|
+
if (!ctx)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (ctx.resolveCapability) {
|
|
9
|
+
return ctx.resolveCapability('html-renderer');
|
|
10
|
+
}
|
|
11
|
+
return ctx.getHtmlRenderer?.();
|
|
12
|
+
}
|
|
13
|
+
export class HtmlSegment extends RichSegment {
|
|
14
|
+
segmentType = 'html';
|
|
15
|
+
type = 'html';
|
|
16
|
+
async render(mode, ctx) {
|
|
17
|
+
if (mode === RICH_SEGMENT_MODE.ORIGIN) {
|
|
18
|
+
return this.toJSON();
|
|
19
|
+
}
|
|
20
|
+
if (mode === RICH_SEGMENT_MODE.TEXT) {
|
|
21
|
+
if (typeof this.data.text === 'string' && this.data.text.length > 0) {
|
|
22
|
+
return segment.text(this.data.text);
|
|
23
|
+
}
|
|
24
|
+
const html = typeof this.data.html === 'string' ? this.data.html : '';
|
|
25
|
+
return segment.text(html ? htmlToFallbackText(html) : '');
|
|
26
|
+
}
|
|
27
|
+
if (mode === RICH_SEGMENT_MODE.IMAGE) {
|
|
28
|
+
const html = typeof this.data.html === 'string' ? this.data.html : '';
|
|
29
|
+
if (!html) {
|
|
30
|
+
return segment.text('');
|
|
31
|
+
}
|
|
32
|
+
const renderer = await resolveHtmlRenderer(ctx);
|
|
33
|
+
if (!renderer) {
|
|
34
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const result = await renderer.render(html, {
|
|
38
|
+
width: typeof this.data.width === 'number' ? this.data.width : 540,
|
|
39
|
+
format: 'png',
|
|
40
|
+
backgroundColor: typeof this.data.backgroundColor === 'string' ? this.data.backgroundColor : '#d8dce3',
|
|
41
|
+
});
|
|
42
|
+
if (result.format !== 'png' || typeof result.data !== 'object') {
|
|
43
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
44
|
+
}
|
|
45
|
+
const base64 = Buffer.from(result.data).toString('base64');
|
|
46
|
+
const fileName = typeof this.data.fileName === 'string' ? this.data.fileName : 'card.png';
|
|
47
|
+
return segment('image', { url: `base64://${base64}`, name: fileName });
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function wrapHtmlSegment(data) {
|
|
57
|
+
const html = typeof data.html === 'string' ? data.html : '';
|
|
58
|
+
return new HtmlSegment({
|
|
59
|
+
html,
|
|
60
|
+
text: typeof data.text === 'string' ? data.text : undefined,
|
|
61
|
+
width: typeof data.width === 'number' ? data.width : undefined,
|
|
62
|
+
backgroundColor: typeof data.backgroundColor === 'string' ? data.backgroundColor : undefined,
|
|
63
|
+
fileName: typeof data.fileName === 'string' ? data.fileName : undefined,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import './builtins.js';
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
export * from './registry.js';
|
|
4
|
+
export * from './capabilities.js';
|
|
5
|
+
export { DEFAULT_OUTBOUND_RICH_SEGMENT_POLICY, resetBuiltinRichSegmentKindsForTests, } from './builtins.js';
|
|
6
|
+
export * from './base.js';
|
|
7
|
+
export * from './qrcode-segment.js';
|
|
8
|
+
export * from './html-segment.js';
|
|
9
|
+
export * from './markdown-segment.js';
|
|
10
|
+
export * from './tts-segment.js';
|
|
11
|
+
export * from './markdown-to-text.js';
|
|
12
|
+
export * from './resolve.js';
|
|
13
|
+
export * from './adapter-policies.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import './builtins.js';
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
export * from './registry.js';
|
|
4
|
+
export * from './capabilities.js';
|
|
5
|
+
export { DEFAULT_OUTBOUND_RICH_SEGMENT_POLICY, resetBuiltinRichSegmentKindsForTests, } from './builtins.js';
|
|
6
|
+
export * from './base.js';
|
|
7
|
+
export * from './qrcode-segment.js';
|
|
8
|
+
export * from './html-segment.js';
|
|
9
|
+
export * from './markdown-segment.js';
|
|
10
|
+
export * from './tts-segment.js';
|
|
11
|
+
export * from './markdown-to-text.js';
|
|
12
|
+
export * from './resolve.js';
|
|
13
|
+
export * from './adapter-policies.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RichSegment } from './base.js';
|
|
2
|
+
import { type RichSegmentRenderContext, type RichSegmentRenderResult } from './types.js';
|
|
3
|
+
export interface MarkdownSegmentData {
|
|
4
|
+
content: string;
|
|
5
|
+
width?: number;
|
|
6
|
+
backgroundColor?: string;
|
|
7
|
+
fileName?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class MarkdownSegment extends RichSegment<MarkdownSegmentData> {
|
|
10
|
+
readonly segmentType: "markdown";
|
|
11
|
+
readonly type: "markdown";
|
|
12
|
+
render(mode: string, ctx?: RichSegmentRenderContext): Promise<RichSegmentRenderResult>;
|
|
13
|
+
}
|
|
14
|
+
export declare function wrapMarkdownSegment(data: Record<string, unknown>): MarkdownSegment;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { segment } from '../../utils.js';
|
|
2
|
+
import { RichSegment } from './base.js';
|
|
3
|
+
import { markdownToHtmlForRender, markdownToPlainText } from './markdown-to-text.js';
|
|
4
|
+
import { RICH_SEGMENT_MODE } from './types.js';
|
|
5
|
+
async function resolveHtmlRenderer(ctx) {
|
|
6
|
+
if (!ctx)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (ctx.resolveCapability) {
|
|
9
|
+
return ctx.resolveCapability('html-renderer');
|
|
10
|
+
}
|
|
11
|
+
return ctx.getHtmlRenderer?.();
|
|
12
|
+
}
|
|
13
|
+
export class MarkdownSegment extends RichSegment {
|
|
14
|
+
segmentType = 'markdown';
|
|
15
|
+
type = 'markdown';
|
|
16
|
+
async render(mode, ctx) {
|
|
17
|
+
if (mode === RICH_SEGMENT_MODE.ORIGIN) {
|
|
18
|
+
return { type: 'markdown', data: { content: this.data.content } };
|
|
19
|
+
}
|
|
20
|
+
if (mode === RICH_SEGMENT_MODE.TEXT) {
|
|
21
|
+
return segment.text(markdownToPlainText(this.data.content));
|
|
22
|
+
}
|
|
23
|
+
if (mode === RICH_SEGMENT_MODE.IMAGE) {
|
|
24
|
+
const renderer = await resolveHtmlRenderer(ctx);
|
|
25
|
+
if (!renderer) {
|
|
26
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const html = markdownToHtmlForRender(this.data.content);
|
|
30
|
+
const result = await renderer.render(html, {
|
|
31
|
+
width: typeof this.data.width === 'number' ? this.data.width : 540,
|
|
32
|
+
format: 'png',
|
|
33
|
+
backgroundColor: typeof this.data.backgroundColor === 'string' ? this.data.backgroundColor : '#ffffff',
|
|
34
|
+
});
|
|
35
|
+
if (result.format !== 'png' || typeof result.data !== 'object') {
|
|
36
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
37
|
+
}
|
|
38
|
+
const base64 = Buffer.from(result.data).toString('base64');
|
|
39
|
+
const fileName = typeof this.data.fileName === 'string' ? this.data.fileName : 'markdown.png';
|
|
40
|
+
return segment('image', { url: `base64://${base64}`, name: fileName });
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function wrapMarkdownSegment(data) {
|
|
50
|
+
const content = typeof data.content === 'string'
|
|
51
|
+
? data.content
|
|
52
|
+
: typeof data.text === 'string'
|
|
53
|
+
? data.text
|
|
54
|
+
: '';
|
|
55
|
+
return new MarkdownSegment({
|
|
56
|
+
content,
|
|
57
|
+
width: typeof data.width === 'number' ? data.width : undefined,
|
|
58
|
+
backgroundColor: typeof data.backgroundColor === 'string' ? data.backgroundColor : undefined,
|
|
59
|
+
fileName: typeof data.fileName === 'string' ? data.fileName : undefined,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** 将 Markdown 转为可读纯文本(出站 text 降级用) */
|
|
2
|
+
export function markdownToPlainText(md) {
|
|
3
|
+
let text = md;
|
|
4
|
+
text = text.replace(/```[\s\S]*?```/g, (block) => {
|
|
5
|
+
const inner = block.replace(/^```[^\n]*\n?/, '').replace(/\n?```$/, '');
|
|
6
|
+
return inner.trim() ? `${inner.trim()}\n` : '';
|
|
7
|
+
});
|
|
8
|
+
text = text.replace(/`([^`]+)`/g, '$1');
|
|
9
|
+
text = text.replace(/!\[[^\]]*\]\([^)]*\)/g, '');
|
|
10
|
+
text = text.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1');
|
|
11
|
+
text = text.replace(/^#{1,6}\s+/gm, '');
|
|
12
|
+
text = text.replace(/^\s*>\s?/gm, '');
|
|
13
|
+
text = text.replace(/^\s*[-*+]\s+/gm, '');
|
|
14
|
+
text = text.replace(/\*\*([^*]+)\*\*/g, '$1');
|
|
15
|
+
text = text.replace(/__([^_]+)__/g, '$1');
|
|
16
|
+
text = text.replace(/\*([^*]+)\*/g, '$1');
|
|
17
|
+
text = text.replace(/_([^_]+)_/g, '$1');
|
|
18
|
+
text = text.replace(/~~([^~]+)~~/g, '$1');
|
|
19
|
+
return text.trim();
|
|
20
|
+
}
|
|
21
|
+
export function markdownToHtmlForRender(md) {
|
|
22
|
+
const escaped = md
|
|
23
|
+
.replace(/&/g, '&')
|
|
24
|
+
.replace(/</g, '<')
|
|
25
|
+
.replace(/>/g, '>');
|
|
26
|
+
return `<pre style="white-space:pre-wrap;font-family:sans-serif;font-size:14px;line-height:1.5;padding:16px;">${escaped}</pre>`;
|
|
27
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MessageElement } from '../../types.js';
|
|
2
|
+
import { type GenerateQrCodeOptions } from '../generated-qrcode.js';
|
|
3
|
+
import { RichSegment } from './base.js';
|
|
4
|
+
import { type RichSegmentRenderContext, type RichSegmentRenderResult } from './types.js';
|
|
5
|
+
export interface QrcodeSegmentData extends GenerateQrCodeOptions {
|
|
6
|
+
text: string;
|
|
7
|
+
/** process origin 模式终端渲染时使用 */
|
|
8
|
+
small?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function readQrcodeSegmentData(data: Record<string, unknown>): QrcodeSegmentData;
|
|
11
|
+
export declare class QrcodeSegment extends RichSegment<QrcodeSegmentData> {
|
|
12
|
+
readonly segmentType: "qrcode";
|
|
13
|
+
readonly type: "qrcode";
|
|
14
|
+
render(mode: string, _ctx?: RichSegmentRenderContext): Promise<RichSegmentRenderResult>;
|
|
15
|
+
}
|
|
16
|
+
export declare function wrapQrcodeSegment(data: Record<string, unknown>): QrcodeSegment;
|
|
17
|
+
/** process endpoint:origin qrcode 段 → 终端 ASCII + 文本占位 */
|
|
18
|
+
export declare function interpretOriginQrcodeForProcess(content: MessageElement | string | (MessageElement | string)[]): Promise<MessageElement | string | (MessageElement | string)[]>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { segment } from '../../utils.js';
|
|
2
|
+
import { GeneratedQrCode } from '../generated-qrcode.js';
|
|
3
|
+
import { RichSegment } from './base.js';
|
|
4
|
+
import { RICH_SEGMENT_MODE } from './types.js';
|
|
5
|
+
export function readQrcodeSegmentData(data) {
|
|
6
|
+
const text = typeof data.text === 'string' ? data.text : '';
|
|
7
|
+
if (!text) {
|
|
8
|
+
throw new Error('qrcode segment: missing data.text');
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
text,
|
|
12
|
+
width: typeof data.width === 'number' ? data.width : undefined,
|
|
13
|
+
margin: typeof data.margin === 'number' ? data.margin : undefined,
|
|
14
|
+
errorCorrectionLevel: data.errorCorrectionLevel === 'L'
|
|
15
|
+
|| data.errorCorrectionLevel === 'M'
|
|
16
|
+
|| data.errorCorrectionLevel === 'Q'
|
|
17
|
+
|| data.errorCorrectionLevel === 'H'
|
|
18
|
+
? data.errorCorrectionLevel
|
|
19
|
+
: undefined,
|
|
20
|
+
small: data.small === true ? true : undefined,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export class QrcodeSegment extends RichSegment {
|
|
24
|
+
segmentType = 'qrcode';
|
|
25
|
+
type = 'qrcode';
|
|
26
|
+
async render(mode, _ctx) {
|
|
27
|
+
if (mode === RICH_SEGMENT_MODE.ORIGIN) {
|
|
28
|
+
return this.toJSON();
|
|
29
|
+
}
|
|
30
|
+
if (mode === RICH_SEGMENT_MODE.TEXT) {
|
|
31
|
+
return segment.text(`[二维码] ${this.data.text}`);
|
|
32
|
+
}
|
|
33
|
+
if (mode === RICH_SEGMENT_MODE.IMAGE) {
|
|
34
|
+
const qr = await GeneratedQrCode.generate(this.data.text, this.data);
|
|
35
|
+
return segment('image', {
|
|
36
|
+
url: qr.toDataUrl(),
|
|
37
|
+
base64: qr.toString('base64'),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, _ctx);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function wrapQrcodeSegment(data) {
|
|
44
|
+
return new QrcodeSegment(readQrcodeSegmentData(data));
|
|
45
|
+
}
|
|
46
|
+
/** process endpoint:origin qrcode 段 → 终端 ASCII + 文本占位 */
|
|
47
|
+
export async function interpretOriginQrcodeForProcess(content) {
|
|
48
|
+
const items = Array.isArray(content) ? content : [content];
|
|
49
|
+
const out = [];
|
|
50
|
+
let changed = false;
|
|
51
|
+
for (const item of items) {
|
|
52
|
+
if (typeof item === 'string') {
|
|
53
|
+
out.push(item);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (item.type !== 'qrcode') {
|
|
57
|
+
out.push(item);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
changed = true;
|
|
61
|
+
const payload = readQrcodeSegmentData(item.data ?? {});
|
|
62
|
+
const qr = await GeneratedQrCode.generate(payload.text, payload);
|
|
63
|
+
await qr.printToTerminal({ small: payload.small ?? true });
|
|
64
|
+
out.push(segment.text(`[二维码] ${payload.text}`));
|
|
65
|
+
}
|
|
66
|
+
if (!changed)
|
|
67
|
+
return content;
|
|
68
|
+
if (out.length === 0)
|
|
69
|
+
return segment.text('');
|
|
70
|
+
if (out.length === 1)
|
|
71
|
+
return out[0];
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OutboundRichSegmentPolicy, RichSegmentKindDefinition } from './types.js';
|
|
2
|
+
export declare class RichSegmentRegistry {
|
|
3
|
+
#private;
|
|
4
|
+
register(definition: RichSegmentKindDefinition): void;
|
|
5
|
+
has(kind: string): boolean;
|
|
6
|
+
get(kind: string): RichSegmentKindDefinition | undefined;
|
|
7
|
+
list(): RichSegmentKindDefinition[];
|
|
8
|
+
buildDefaultPolicy(): OutboundRichSegmentPolicy;
|
|
9
|
+
resolveMode(policy: OutboundRichSegmentPolicy, kind: string): string;
|
|
10
|
+
wrap(kind: string, data: Record<string, unknown>): import("./types.js").RichSegmentLike;
|
|
11
|
+
/** 测试隔离:清空后需重新 register builtins */
|
|
12
|
+
clearForTests(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare const RICH_SEGMENT_FALLBACK_MODE = "origin";
|
|
15
|
+
export declare const richSegmentRegistry: RichSegmentRegistry;
|
|
16
|
+
export declare function registerRichSegmentKind(definition: RichSegmentKindDefinition): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export class RichSegmentRegistry {
|
|
2
|
+
#kinds = new Map();
|
|
3
|
+
register(definition) {
|
|
4
|
+
if (this.#kinds.has(definition.kind)) {
|
|
5
|
+
throw new Error(`Rich segment kind already registered: ${definition.kind}`);
|
|
6
|
+
}
|
|
7
|
+
if (!definition.modes.includes(definition.defaultMode)) {
|
|
8
|
+
throw new Error(`Rich segment ${definition.kind}: defaultMode "${definition.defaultMode}" not in modes`);
|
|
9
|
+
}
|
|
10
|
+
this.#kinds.set(definition.kind, definition);
|
|
11
|
+
}
|
|
12
|
+
has(kind) {
|
|
13
|
+
return this.#kinds.has(kind);
|
|
14
|
+
}
|
|
15
|
+
get(kind) {
|
|
16
|
+
return this.#kinds.get(kind);
|
|
17
|
+
}
|
|
18
|
+
list() {
|
|
19
|
+
return [...this.#kinds.values()];
|
|
20
|
+
}
|
|
21
|
+
buildDefaultPolicy() {
|
|
22
|
+
const policy = {};
|
|
23
|
+
for (const def of this.#kinds.values()) {
|
|
24
|
+
policy[def.kind] = def.defaultMode;
|
|
25
|
+
}
|
|
26
|
+
return policy;
|
|
27
|
+
}
|
|
28
|
+
resolveMode(policy, kind) {
|
|
29
|
+
const def = this.#kinds.get(kind);
|
|
30
|
+
const requested = policy[kind] ?? def?.defaultMode ?? RICH_SEGMENT_FALLBACK_MODE;
|
|
31
|
+
if (def && !def.modes.includes(requested)) {
|
|
32
|
+
return def.defaultMode;
|
|
33
|
+
}
|
|
34
|
+
return requested;
|
|
35
|
+
}
|
|
36
|
+
wrap(kind, data) {
|
|
37
|
+
const def = this.#kinds.get(kind);
|
|
38
|
+
if (!def) {
|
|
39
|
+
throw new Error(`Unknown rich segment kind: ${kind}`);
|
|
40
|
+
}
|
|
41
|
+
return def.wrap(data);
|
|
42
|
+
}
|
|
43
|
+
/** 测试隔离:清空后需重新 register builtins */
|
|
44
|
+
clearForTests() {
|
|
45
|
+
this.#kinds.clear();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export const RICH_SEGMENT_FALLBACK_MODE = 'origin';
|
|
49
|
+
export const richSegmentRegistry = new RichSegmentRegistry();
|
|
50
|
+
export function registerRichSegmentKind(definition) {
|
|
51
|
+
richSegmentRegistry.register(definition);
|
|
52
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SendContent } from '../../types.js';
|
|
2
|
+
import { type OutboundRichSegmentPolicy, type RichSegmentRenderContext } from './types.js';
|
|
3
|
+
export declare function hasRichSegment(content: SendContent | undefined): boolean;
|
|
4
|
+
/** 按 Adapter 出站策略在 renderSendMessage 首步统一渲染富媒体段 */
|
|
5
|
+
export declare function resolveRichSegments(content: SendContent, policy: OutboundRichSegmentPolicy, ctx?: RichSegmentRenderContext): Promise<SendContent>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { isRichSegment, richSegmentKind } from './base.js';
|
|
2
|
+
import { richSegmentRegistry } from './registry.js';
|
|
3
|
+
import { RICH_SEGMENT_MODE } from './types.js';
|
|
4
|
+
import { CONTENT_CHAIN_STAGE } from '@zhin.js/logger';
|
|
5
|
+
function asArray(content) {
|
|
6
|
+
return Array.isArray(content) ? content : [content];
|
|
7
|
+
}
|
|
8
|
+
function packSegments(out) {
|
|
9
|
+
if (out.length === 0)
|
|
10
|
+
return { type: 'text', data: { text: '' } };
|
|
11
|
+
if (out.length === 1)
|
|
12
|
+
return out[0];
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
function appendRendered(out, rendered) {
|
|
16
|
+
if (Array.isArray(rendered)) {
|
|
17
|
+
out.push(...rendered);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
out.push(rendered);
|
|
21
|
+
}
|
|
22
|
+
function primarySegmentType(rendered) {
|
|
23
|
+
if (typeof rendered === 'string')
|
|
24
|
+
return 'text';
|
|
25
|
+
if (Array.isArray(rendered)) {
|
|
26
|
+
const first = rendered[0];
|
|
27
|
+
if (typeof first === 'string')
|
|
28
|
+
return 'text';
|
|
29
|
+
const t = first?.type;
|
|
30
|
+
return typeof t === 'string' ? t : 'unknown';
|
|
31
|
+
}
|
|
32
|
+
const t = rendered.type;
|
|
33
|
+
return typeof t === 'string' ? t : 'unknown';
|
|
34
|
+
}
|
|
35
|
+
function detectRichSegmentFallback(mode, renderedType) {
|
|
36
|
+
if (mode === RICH_SEGMENT_MODE.IMAGE && renderedType !== 'image')
|
|
37
|
+
return true;
|
|
38
|
+
if (mode === RICH_SEGMENT_MODE.AUDIO && renderedType !== 'audio')
|
|
39
|
+
return true;
|
|
40
|
+
if (mode === RICH_SEGMENT_MODE.FILE && renderedType !== 'file')
|
|
41
|
+
return true;
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
export function hasRichSegment(content) {
|
|
45
|
+
if (content == null)
|
|
46
|
+
return false;
|
|
47
|
+
return asArray(content).some((item) => {
|
|
48
|
+
if (typeof item === 'string')
|
|
49
|
+
return false;
|
|
50
|
+
return richSegmentKind(item) != null || isRichSegment(item);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** 按 Adapter 出站策略在 renderSendMessage 首步统一渲染富媒体段 */
|
|
54
|
+
export async function resolveRichSegments(content, policy, ctx) {
|
|
55
|
+
if (!hasRichSegment(content)) {
|
|
56
|
+
return content;
|
|
57
|
+
}
|
|
58
|
+
const items = asArray(content);
|
|
59
|
+
const out = [];
|
|
60
|
+
for (const item of items) {
|
|
61
|
+
if (typeof item === 'string') {
|
|
62
|
+
out.push(item);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const kind = isRichSegment(item) ? item.segmentType : richSegmentKind(item);
|
|
66
|
+
if (!kind || !richSegmentRegistry.has(kind)) {
|
|
67
|
+
out.push(item);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const rich = isRichSegment(item)
|
|
71
|
+
? item
|
|
72
|
+
: richSegmentRegistry.wrap(kind, item.data ?? {});
|
|
73
|
+
const mode = richSegmentRegistry.resolveMode(policy, kind);
|
|
74
|
+
const rendered = await rich.render(mode, ctx);
|
|
75
|
+
const renderedType = primarySegmentType(rendered);
|
|
76
|
+
const fallback = detectRichSegmentFallback(mode, renderedType);
|
|
77
|
+
ctx?.logContentChain?.({
|
|
78
|
+
stage: CONTENT_CHAIN_STAGE.RICH_SEGMENT,
|
|
79
|
+
kind,
|
|
80
|
+
mode,
|
|
81
|
+
fallback,
|
|
82
|
+
result: renderedType,
|
|
83
|
+
});
|
|
84
|
+
appendRendered(out, rendered);
|
|
85
|
+
}
|
|
86
|
+
return packSegments(out);
|
|
87
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { RichSegment } from './base.js';
|
|
2
|
+
import { type RichSegmentRenderContext, type RichSegmentRenderResult } from './types.js';
|
|
3
|
+
export interface TtsSegmentData {
|
|
4
|
+
text: string;
|
|
5
|
+
voice?: string;
|
|
6
|
+
provider?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class TtsSegment extends RichSegment<TtsSegmentData> {
|
|
9
|
+
readonly segmentType: "tts";
|
|
10
|
+
readonly type: "tts";
|
|
11
|
+
render(mode: string, ctx?: RichSegmentRenderContext): Promise<RichSegmentRenderResult>;
|
|
12
|
+
}
|
|
13
|
+
export declare function wrapTtsSegment(data: Record<string, unknown>): TtsSegment;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { segment } from '../../utils.js';
|
|
2
|
+
import { RichSegment } from './base.js';
|
|
3
|
+
import { RICH_SEGMENT_MODE } from './types.js';
|
|
4
|
+
async function resolveSpeechPipeline(ctx) {
|
|
5
|
+
if (!ctx?.resolveCapability)
|
|
6
|
+
return undefined;
|
|
7
|
+
return ctx.resolveCapability('speech');
|
|
8
|
+
}
|
|
9
|
+
export class TtsSegment extends RichSegment {
|
|
10
|
+
segmentType = 'tts';
|
|
11
|
+
type = 'tts';
|
|
12
|
+
async render(mode, ctx) {
|
|
13
|
+
if (mode === RICH_SEGMENT_MODE.ORIGIN) {
|
|
14
|
+
return this.toJSON();
|
|
15
|
+
}
|
|
16
|
+
const text = typeof this.data.text === 'string' ? this.data.text : '';
|
|
17
|
+
if (mode === RICH_SEGMENT_MODE.TEXT) {
|
|
18
|
+
return segment.text(text);
|
|
19
|
+
}
|
|
20
|
+
if (mode === RICH_SEGMENT_MODE.AUDIO) {
|
|
21
|
+
if (!text.trim()) {
|
|
22
|
+
return segment.text('');
|
|
23
|
+
}
|
|
24
|
+
const pipeline = await resolveSpeechPipeline(ctx);
|
|
25
|
+
if (!pipeline) {
|
|
26
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const result = await pipeline.synthesize({
|
|
30
|
+
text,
|
|
31
|
+
voice: typeof this.data.voice === 'string' ? this.data.voice : undefined,
|
|
32
|
+
provider: typeof this.data.provider === 'string' ? this.data.provider : undefined,
|
|
33
|
+
});
|
|
34
|
+
const base64 = result.data.toString('base64');
|
|
35
|
+
const mime = result.format === 'wav' ? 'audio/wav' : 'audio/mpeg';
|
|
36
|
+
return segment('audio', { url: `data:${mime};base64,${base64}`, format: result.format });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function wrapTtsSegment(data) {
|
|
46
|
+
return new TtsSegment({
|
|
47
|
+
text: String(data.text ?? ''),
|
|
48
|
+
voice: typeof data.voice === 'string' ? data.voice : undefined,
|
|
49
|
+
provider: typeof data.provider === 'string' ? data.provider : undefined,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { MessageElement } from '../../types.js';
|
|
2
|
+
import type { ContentChainLogFields } from '@zhin.js/logger';
|
|
3
|
+
/** 内置 kind 常量(外部可增删,registry 为 SSOT) */
|
|
4
|
+
export declare const BUILTIN_RICH_SEGMENT_KINDS: {
|
|
5
|
+
readonly QRCODE: "qrcode";
|
|
6
|
+
readonly HTML: "html";
|
|
7
|
+
readonly MARKDOWN: "markdown";
|
|
8
|
+
readonly TTS: "tts";
|
|
9
|
+
};
|
|
10
|
+
export type BuiltinRichSegmentKind = (typeof BUILTIN_RICH_SEGMENT_KINDS)[keyof typeof BUILTIN_RICH_SEGMENT_KINDS];
|
|
11
|
+
/** 通用 mode 名;各 kind 在 registry 中声明支持的子集 */
|
|
12
|
+
export declare const RICH_SEGMENT_MODE: {
|
|
13
|
+
readonly ORIGIN: "origin";
|
|
14
|
+
readonly TEXT: "text";
|
|
15
|
+
readonly IMAGE: "image";
|
|
16
|
+
readonly FILE: "file";
|
|
17
|
+
readonly URL: "url";
|
|
18
|
+
readonly AUDIO: "audio";
|
|
19
|
+
readonly VIDEO: "video";
|
|
20
|
+
};
|
|
21
|
+
export type RichSegmentMode = (typeof RICH_SEGMENT_MODE)[keyof typeof RICH_SEGMENT_MODE] | string;
|
|
22
|
+
/** 任意已注册 kind → 渲染 mode */
|
|
23
|
+
export type OutboundRichSegmentPolicy = Record<string, string>;
|
|
24
|
+
/** @deprecated 使用 OutboundRichSegmentPolicy;保留别名便于迁移 */
|
|
25
|
+
export type RichSegmentKind = string;
|
|
26
|
+
export type RichRenderMode = string;
|
|
27
|
+
/** html-renderer 可选包契约 */
|
|
28
|
+
export interface HtmlRendererForRichSegment {
|
|
29
|
+
render(html: string, options?: {
|
|
30
|
+
width?: number;
|
|
31
|
+
format?: 'png';
|
|
32
|
+
backgroundColor?: string;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
format: string;
|
|
35
|
+
data: Buffer | string;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
/** speech 可选包契约(@zhin.js/speech) */
|
|
39
|
+
export interface SpeechPipelineForRichSegment {
|
|
40
|
+
transcribe(input: {
|
|
41
|
+
data: Buffer;
|
|
42
|
+
mimeType?: string;
|
|
43
|
+
}): Promise<string>;
|
|
44
|
+
synthesize(input: {
|
|
45
|
+
text: string;
|
|
46
|
+
voice?: string;
|
|
47
|
+
format?: 'mp3' | 'wav';
|
|
48
|
+
speed?: number;
|
|
49
|
+
provider?: string;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
data: Buffer;
|
|
52
|
+
format: 'mp3' | 'wav';
|
|
53
|
+
}>;
|
|
54
|
+
}
|
|
55
|
+
/** 未来 media-pipeline / ffmpeg 等 optional 包可复用同一 id */
|
|
56
|
+
export type RichSegmentCapabilityId = 'html-renderer' | 'speech' | 'media-pipeline' | string;
|
|
57
|
+
export interface RichSegmentRenderContext {
|
|
58
|
+
/** 按 id 懒加载能力(core 或 optional 包 register loader) */
|
|
59
|
+
resolveCapability: <T>(id: RichSegmentCapabilityId) => Promise<T | undefined>;
|
|
60
|
+
/** @deprecated 请用 resolveCapability('html-renderer') */
|
|
61
|
+
getHtmlRenderer?: () => Promise<HtmlRendererForRichSegment | undefined>;
|
|
62
|
+
/** 可选:rich_segment stage 结构化日志 */
|
|
63
|
+
logContentChain?: (fields: ContentChainLogFields) => void;
|
|
64
|
+
warn?: (message: string) => void;
|
|
65
|
+
}
|
|
66
|
+
export type RichSegmentRenderResult = MessageElement | MessageElement[];
|
|
67
|
+
export interface RichSegmentLike {
|
|
68
|
+
readonly segmentType: string;
|
|
69
|
+
render(mode: string, ctx?: RichSegmentRenderContext): Promise<RichSegmentRenderResult>;
|
|
70
|
+
}
|
|
71
|
+
export interface RichSegmentKindDefinition {
|
|
72
|
+
kind: string;
|
|
73
|
+
/** policy 未指定时使用的 mode */
|
|
74
|
+
defaultMode: string;
|
|
75
|
+
/** 该 kind 支持的 mode 列表(policy 非法值会回退 defaultMode) */
|
|
76
|
+
modes: readonly string[];
|
|
77
|
+
wrap: (data: Record<string, unknown>) => RichSegmentLike;
|
|
78
|
+
}
|
|
79
|
+
export interface RichSegmentCapabilityLoaderOptions {
|
|
80
|
+
warn?: (message: string) => void;
|
|
81
|
+
getConfig?: () => Record<string, unknown> | undefined;
|
|
82
|
+
logContentChain?: RichSegmentRenderContext['logContentChain'];
|
|
83
|
+
}
|
|
84
|
+
export type RichSegmentCapabilityLoader = (options: RichSegmentCapabilityLoaderOptions) => Promise<unknown>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** 内置 kind 常量(外部可增删,registry 为 SSOT) */
|
|
2
|
+
export const BUILTIN_RICH_SEGMENT_KINDS = {
|
|
3
|
+
QRCODE: 'qrcode',
|
|
4
|
+
HTML: 'html',
|
|
5
|
+
MARKDOWN: 'markdown',
|
|
6
|
+
TTS: 'tts',
|
|
7
|
+
};
|
|
8
|
+
/** 通用 mode 名;各 kind 在 registry 中声明支持的子集 */
|
|
9
|
+
export const RICH_SEGMENT_MODE = {
|
|
10
|
+
ORIGIN: 'origin',
|
|
11
|
+
TEXT: 'text',
|
|
12
|
+
IMAGE: 'image',
|
|
13
|
+
FILE: 'file',
|
|
14
|
+
URL: 'url',
|
|
15
|
+
AUDIO: 'audio',
|
|
16
|
+
VIDEO: 'video',
|
|
17
|
+
};
|
package/lib/built/roles.d.ts
CHANGED
|
@@ -12,4 +12,3 @@ export declare function hasSenderRole(roles: Iterable<SenderRole>, role: SenderR
|
|
|
12
12
|
export declare function formatSenderRolesForLabel(roles: readonly SenderRole[]): string;
|
|
13
13
|
/** 剥离用户正文里自造的发送者前缀 */
|
|
14
14
|
export declare function stripUserSpoofedSenderPrefix(rawContent: string): string;
|
|
15
|
-
//# sourceMappingURL=roles.d.ts.map
|
package/lib/built/roles.js
CHANGED
|
@@ -7,4 +7,3 @@ export declare function shouldBindProcessStdin(): boolean;
|
|
|
7
7
|
export declare function isInteractiveStdin(): boolean;
|
|
8
8
|
export declare function isDenoDeploy(): boolean;
|
|
9
9
|
export declare function bindStdin(onChunk: (chunk: string) => void): () => void;
|
|
10
|
-
//# sourceMappingURL=runtime-io.d.ts.map
|
package/lib/built/runtime-io.js
CHANGED