File size: 2,746 Bytes
6111b2b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**

 * Vision Bridge default configuration values.

 */

const FORCED_VISION_BRIDGE_MODELS = new Set<string>([
  // opencode-go/opencode-zen providers: synced capabilities overstate vision support
  // (modalities_input includes "image" from provider catalog), but the actual backend
  // models used by these providers do not have native vision. Force Vision Bridge to
  // convert images to text descriptions for these models.
  "opencode-go/deepseek-v4-flash",
  "opencode-go/deepseek-v4-pro",
  "opencode-go/kimi-k2.6",
  "opencode-go/kimi-k2.5",
  "opencode-go/glm-5.1",
  "opencode-go/glm-5",
  "opencode-go/qwen3.6-plus",
  "opencode-go/qwen3.5-plus",
  "opencode-zen/deepseek-v4-flash",
  "opencode-zen/deepseek-v4-pro",
]);

export function isVisionBridgeForcedModel(model: string | null | undefined): boolean {
  if (!model) return false;
  const lowerModel = model.trim().toLowerCase();
  if (FORCED_VISION_BRIDGE_MODELS.has(lowerModel)) return true;
  // Also check just the model name (after /) for backward compatibility
  const normalizedModel = lowerModel.includes("/")
    ? lowerModel.split("/").pop() || lowerModel
    : lowerModel;
  return FORCED_VISION_BRIDGE_MODELS.has(normalizedModel);
}

export const VISION_BRIDGE_DEFAULTS = {
  enabled: true,
  model: "openai/gpt-4o-mini",
  prompt:
    "Describe this image concisely in 2-3 sentences. Focus on the most relevant visual details.",
  timeoutMs: 30000,
  maxImagesPerRequest: 10,
} as const;

/**

 * Settings keys for Vision Bridge (to be stored in key_value table).

 */
export const VISION_BRIDGE_SETTINGS_KEYS = [
  "visionBridgeEnabled",
  "visionBridgeModel",
  "visionBridgePrompt",
  "visionBridgeTimeout",
  "visionBridgeMaxImages",
] as const;

export type VisionBridgeSettings = {
  visionBridgeEnabled?: boolean;
  visionBridgeModel?: string;
  visionBridgePrompt?: string;
  visionBridgeTimeout?: number;
  visionBridgeMaxImages?: number;
};

export type VisionBridgeConfig = {
  enabled: boolean;
  model: string;
  prompt: string;
  timeoutMs: number;
  maxImages: number;
};

/**

 * Merge settings with defaults to produce a complete config.

 */
export function getVisionBridgeConfig(

  settings: VisionBridgeSettings | undefined | null = {}

): VisionBridgeConfig {
  const s = settings ?? {};
  return {
    enabled: s.visionBridgeEnabled ?? VISION_BRIDGE_DEFAULTS.enabled,
    model: s.visionBridgeModel ?? VISION_BRIDGE_DEFAULTS.model,
    prompt: s.visionBridgePrompt ?? VISION_BRIDGE_DEFAULTS.prompt,
    timeoutMs: s.visionBridgeTimeout ?? VISION_BRIDGE_DEFAULTS.timeoutMs,
    maxImages: s.visionBridgeMaxImages ?? VISION_BRIDGE_DEFAULTS.maxImagesPerRequest,
  };
}