mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-03 14:10:43 +00:00
feat(channels): add structured attachment support for file handling
- Add Attachment interface with type, data, filePath, mimeType, fileName - Resolve attachments in ChannelBase before prompting bridge - Update DingTalk, Telegram, Weixin adapters to use structured attachments - Clean up placeholder text when files are received - Export Attachment type from base package index This enables proper handling of images and files across all channels, separating attachment metadata from message text. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
3d24a9c3fe
commit
3e0f213ea3
6 changed files with 84 additions and 17 deletions
|
|
@ -238,6 +238,28 @@ export abstract class ChannelBase {
|
|||
promptText = `[Replying to: "${envelope.referencedText}"]\n\n${promptText}`;
|
||||
}
|
||||
|
||||
// Resolve attachments: extract image for bridge, append file paths to text
|
||||
let imageBase64 = envelope.imageBase64;
|
||||
let imageMimeType = envelope.imageMimeType;
|
||||
if (envelope.attachments?.length) {
|
||||
const filePaths: string[] = [];
|
||||
for (const att of envelope.attachments) {
|
||||
if (att.type === 'image' && att.data && !imageBase64) {
|
||||
imageBase64 = att.data;
|
||||
imageMimeType = att.mimeType;
|
||||
} else if (att.filePath) {
|
||||
const label = att.type === 'file' ? 'file' : att.type;
|
||||
const name = att.fileName ? ` "${att.fileName}"` : '';
|
||||
filePaths.push(
|
||||
`User sent a ${label}${name}. It has been saved to: ${att.filePath}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (filePaths.length > 0) {
|
||||
promptText = promptText + '\n\n' + filePaths.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend channel instructions on first message of a session
|
||||
if (this.config.instructions && !this.instructedSessions.has(sessionId)) {
|
||||
promptText = `${this.config.instructions}\n\n${promptText}`;
|
||||
|
|
@ -269,8 +291,8 @@ export abstract class ChannelBase {
|
|||
|
||||
try {
|
||||
const response = await this.bridge.prompt(sessionId, promptText, {
|
||||
imageBase64: envelope.imageBase64,
|
||||
imageMimeType: envelope.imageMimeType,
|
||||
imageBase64,
|
||||
imageMimeType,
|
||||
});
|
||||
|
||||
if (response) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export { SenderGate } from './SenderGate.js';
|
|||
export type { SenderCheckResult } from './SenderGate.js';
|
||||
export { SessionRouter } from './SessionRouter.js';
|
||||
export type {
|
||||
Attachment,
|
||||
BlockStreamingChunkConfig,
|
||||
BlockStreamingCoalesceConfig,
|
||||
ChannelConfig,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,19 @@ export interface ChannelConfig {
|
|||
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
|
||||
}
|
||||
|
||||
export interface Attachment {
|
||||
/** Content category. */
|
||||
type: 'image' | 'file' | 'audio' | 'video';
|
||||
/** Base64-encoded data (for images or small files). */
|
||||
data?: string;
|
||||
/** Absolute path to a local file (for large files saved to disk). */
|
||||
filePath?: string;
|
||||
/** MIME type (e.g. "image/jpeg", "application/pdf"). */
|
||||
mimeType: string;
|
||||
/** Original file name from the platform. */
|
||||
fileName?: string;
|
||||
}
|
||||
|
||||
export interface Envelope {
|
||||
channelName: string;
|
||||
senderId: string;
|
||||
|
|
@ -63,6 +76,8 @@ export interface Envelope {
|
|||
imageBase64?: string;
|
||||
/** MIME type for the image (e.g. "image/jpeg", "image/png"). */
|
||||
imageMimeType?: string;
|
||||
/** Structured attachments (images, files, audio, video). */
|
||||
attachments?: Attachment[];
|
||||
}
|
||||
|
||||
export interface SessionTarget {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue