skema-core 2.1.1 → 2.1.2

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/dist/server.d.mts CHANGED
@@ -451,14 +451,19 @@ declare function isProviderAvailable(provider: AIProvider): boolean;
451
451
  */
452
452
  declare function getAvailableProviders(): AIProvider[];
453
453
 
454
+ type VisionProvider = 'gemini' | 'claude' | 'openai';
455
+ declare const VISION_MODELS: Record<VisionProvider, {
456
+ models: string[];
457
+ default: string;
458
+ }>;
454
459
  interface VisionAnalysisResult {
455
460
  success: boolean;
456
461
  description: string;
457
- provider: AIProvider;
462
+ provider: VisionProvider;
458
463
  error?: string;
459
464
  }
460
465
  interface VisionConfig {
461
- provider: AIProvider;
466
+ provider: VisionProvider;
462
467
  /** API key for vision API (falls back to env vars) */
463
468
  apiKey?: string;
464
469
  /** Model to use for vision */
@@ -471,7 +476,7 @@ declare function analyzeImage(base64Image: string, config: VisionConfig): Promis
471
476
  /**
472
477
  * Check if vision analysis is available for a provider
473
478
  */
474
- declare function isVisionAvailable(provider: AIProvider): boolean;
479
+ declare function isVisionAvailable(provider: VisionProvider): boolean;
475
480
 
476
481
  type AnnotationStatus = 'pending' | 'acknowledged' | 'resolved' | 'dismissed';
477
482
  interface StoredAnnotation {
@@ -538,4 +543,4 @@ declare function onStoreEvent(listener: StoreListener): () => void;
538
543
  */
539
544
  declare function getPendingCount(): number;
540
545
 
541
- export { type AIProviderConfig, type AIRunResult, type AIStreamEvent, type AnnotationStatus, type AIProvider as CLIProvider, DELETE, type DaemonConfig, type DaemonInstance, type DetailedDomSelectionInput, type DomSelectionInput, type DrawingInput, type ExecutionMode, type GeminiCLIEvent, type GeminiCLIOptions, type GestureInput, IMAGE_ANALYSIS_PROMPT, type IncomingMessage, type OutgoingMessage, POST, type ProjectContext, type ProviderName, type StoredAnnotation, type VisionAnalysisResult, type VisionConfig, acknowledgeAnnotation, analyzeImage, buildDetailedDomSelectionPrompt, buildDrawingToCodePrompt, buildFastDomSelectionPrompt, buildGesturePrompt, buildPromptFromAnnotation, clearAnnotations, createGeminiCLIStream, createGeminiRouteHandler, createRevertRouteHandler, dismissAnnotation, getAllAnnotations, getAnnotation, getAvailableProviders as getCLIProviders, getPendingAnnotations, getPendingCount, getTrackedAnnotations, isProviderAvailable, isVisionAvailable, onStoreEvent, queueAnnotation, removeAnnotation, resolveAnnotation, revertAnnotation, runAICLI, runGeminiCLI, spawnAICLI, spawnGeminiCLI, startDaemon };
546
+ export { type AIProviderConfig, type AIRunResult, type AIStreamEvent, type AnnotationStatus, type AIProvider as CLIProvider, DELETE, type DaemonConfig, type DaemonInstance, type DetailedDomSelectionInput, type DomSelectionInput, type DrawingInput, type ExecutionMode, type GeminiCLIEvent, type GeminiCLIOptions, type GestureInput, IMAGE_ANALYSIS_PROMPT, type IncomingMessage, type OutgoingMessage, POST, type ProjectContext, type ProviderName, type StoredAnnotation, VISION_MODELS, type VisionAnalysisResult, type VisionConfig, type VisionProvider, acknowledgeAnnotation, analyzeImage, buildDetailedDomSelectionPrompt, buildDrawingToCodePrompt, buildFastDomSelectionPrompt, buildGesturePrompt, buildPromptFromAnnotation, clearAnnotations, createGeminiCLIStream, createGeminiRouteHandler, createRevertRouteHandler, dismissAnnotation, getAllAnnotations, getAnnotation, getAvailableProviders as getCLIProviders, getPendingAnnotations, getPendingCount, getTrackedAnnotations, isProviderAvailable, isVisionAvailable, onStoreEvent, queueAnnotation, removeAnnotation, resolveAnnotation, revertAnnotation, runAICLI, runGeminiCLI, spawnAICLI, spawnGeminiCLI, startDaemon };
package/dist/server.d.ts CHANGED
@@ -451,14 +451,19 @@ declare function isProviderAvailable(provider: AIProvider): boolean;
451
451
  */
452
452
  declare function getAvailableProviders(): AIProvider[];
453
453
 
454
+ type VisionProvider = 'gemini' | 'claude' | 'openai';
455
+ declare const VISION_MODELS: Record<VisionProvider, {
456
+ models: string[];
457
+ default: string;
458
+ }>;
454
459
  interface VisionAnalysisResult {
455
460
  success: boolean;
456
461
  description: string;
457
- provider: AIProvider;
462
+ provider: VisionProvider;
458
463
  error?: string;
459
464
  }
460
465
  interface VisionConfig {
461
- provider: AIProvider;
466
+ provider: VisionProvider;
462
467
  /** API key for vision API (falls back to env vars) */
463
468
  apiKey?: string;
464
469
  /** Model to use for vision */
@@ -471,7 +476,7 @@ declare function analyzeImage(base64Image: string, config: VisionConfig): Promis
471
476
  /**
472
477
  * Check if vision analysis is available for a provider
473
478
  */
474
- declare function isVisionAvailable(provider: AIProvider): boolean;
479
+ declare function isVisionAvailable(provider: VisionProvider): boolean;
475
480
 
476
481
  type AnnotationStatus = 'pending' | 'acknowledged' | 'resolved' | 'dismissed';
477
482
  interface StoredAnnotation {
@@ -538,4 +543,4 @@ declare function onStoreEvent(listener: StoreListener): () => void;
538
543
  */
539
544
  declare function getPendingCount(): number;
540
545
 
541
- export { type AIProviderConfig, type AIRunResult, type AIStreamEvent, type AnnotationStatus, type AIProvider as CLIProvider, DELETE, type DaemonConfig, type DaemonInstance, type DetailedDomSelectionInput, type DomSelectionInput, type DrawingInput, type ExecutionMode, type GeminiCLIEvent, type GeminiCLIOptions, type GestureInput, IMAGE_ANALYSIS_PROMPT, type IncomingMessage, type OutgoingMessage, POST, type ProjectContext, type ProviderName, type StoredAnnotation, type VisionAnalysisResult, type VisionConfig, acknowledgeAnnotation, analyzeImage, buildDetailedDomSelectionPrompt, buildDrawingToCodePrompt, buildFastDomSelectionPrompt, buildGesturePrompt, buildPromptFromAnnotation, clearAnnotations, createGeminiCLIStream, createGeminiRouteHandler, createRevertRouteHandler, dismissAnnotation, getAllAnnotations, getAnnotation, getAvailableProviders as getCLIProviders, getPendingAnnotations, getPendingCount, getTrackedAnnotations, isProviderAvailable, isVisionAvailable, onStoreEvent, queueAnnotation, removeAnnotation, resolveAnnotation, revertAnnotation, runAICLI, runGeminiCLI, spawnAICLI, spawnGeminiCLI, startDaemon };
546
+ export { type AIProviderConfig, type AIRunResult, type AIStreamEvent, type AnnotationStatus, type AIProvider as CLIProvider, DELETE, type DaemonConfig, type DaemonInstance, type DetailedDomSelectionInput, type DomSelectionInput, type DrawingInput, type ExecutionMode, type GeminiCLIEvent, type GeminiCLIOptions, type GestureInput, IMAGE_ANALYSIS_PROMPT, type IncomingMessage, type OutgoingMessage, POST, type ProjectContext, type ProviderName, type StoredAnnotation, VISION_MODELS, type VisionAnalysisResult, type VisionConfig, type VisionProvider, acknowledgeAnnotation, analyzeImage, buildDetailedDomSelectionPrompt, buildDrawingToCodePrompt, buildFastDomSelectionPrompt, buildGesturePrompt, buildPromptFromAnnotation, clearAnnotations, createGeminiCLIStream, createGeminiRouteHandler, createRevertRouteHandler, dismissAnnotation, getAllAnnotations, getAnnotation, getAvailableProviders as getCLIProviders, getPendingAnnotations, getPendingCount, getTrackedAnnotations, isProviderAvailable, isVisionAvailable, onStoreEvent, queueAnnotation, removeAnnotation, resolveAnnotation, revertAnnotation, runAICLI, runGeminiCLI, spawnAICLI, spawnGeminiCLI, startDaemon };
package/dist/server.js CHANGED
@@ -5,6 +5,10 @@ var generativeAi = require('@google/generative-ai');
5
5
  var ws = require('ws');
6
6
  var fs = require('fs');
7
7
  var path = require('path');
8
+ var ai = require('ai');
9
+ var google = require('@ai-sdk/google');
10
+ var anthropic = require('@ai-sdk/anthropic');
11
+ var openai = require('@ai-sdk/openai');
8
12
 
9
13
  function _interopNamespace(e) {
10
14
  if (e && e.__esModule) return e;
@@ -903,57 +907,83 @@ function getAllProviderStatuses() {
903
907
  claude: getProviderStatus("claude")
904
908
  };
905
909
  }
906
- async function analyzeWithGemini(base64Image, apiKey, model = "gemini-2.5-flash") {
907
- try {
908
- const genAI = new generativeAi.GoogleGenerativeAI(apiKey);
909
- const visionModel = genAI.getGenerativeModel({ model });
910
- const cleanBase64 = base64Image.replace(/^data:image\/\w+;base64,/, "");
911
- const result = await visionModel.generateContent([
912
- IMAGE_ANALYSIS_PROMPT,
913
- {
914
- inlineData: {
915
- data: cleanBase64,
916
- mimeType: "image/png"
917
- }
918
- }
919
- ]);
920
- const response = await result.response;
921
- const text = response.text();
922
- return {
923
- success: true,
924
- description: text,
925
- provider: "gemini"
926
- };
927
- } catch (error) {
928
- const message = error instanceof Error ? error.message : String(error);
929
- console.error("[Vision] Gemini analysis failed:", message);
910
+ var VISION_MODELS = {
911
+ gemini: {
912
+ models: ["gemini-2.5-flash", "gemini-2.5-pro", "gemini-3-flash-preview", "gemini-3-pro-preview"],
913
+ default: "gemini-2.5-flash"
914
+ },
915
+ claude: {
916
+ models: ["claude-haiku-4-5-20251001", "claude-sonnet-4-5-20250929", "claude-opus-4-6"],
917
+ default: "claude-haiku-4-5-20251001"
918
+ },
919
+ openai: {
920
+ models: ["gpt-4o-mini", "gpt-4o", "gpt-4.1", "gpt-5.2"],
921
+ default: "gpt-4o-mini"
922
+ }
923
+ };
924
+ function getProviderModel(provider, apiKey, model) {
925
+ const modelId = model || VISION_MODELS[provider].default;
926
+ switch (provider) {
927
+ case "gemini": {
928
+ const google$1 = google.createGoogleGenerativeAI({ apiKey });
929
+ return google$1(modelId);
930
+ }
931
+ case "claude": {
932
+ const anthropic$1 = anthropic.createAnthropic({ apiKey });
933
+ return anthropic$1(modelId);
934
+ }
935
+ case "openai": {
936
+ const openai$1 = openai.createOpenAI({ apiKey });
937
+ return openai$1(modelId);
938
+ }
939
+ }
940
+ }
941
+ function getEnvVarForProvider(provider) {
942
+ switch (provider) {
943
+ case "gemini":
944
+ return process.env.GEMINI_API_KEY;
945
+ case "claude":
946
+ return process.env.ANTHROPIC_API_KEY;
947
+ case "openai":
948
+ return process.env.OPENAI_API_KEY;
949
+ }
950
+ }
951
+ function getEnvVarName(provider) {
952
+ switch (provider) {
953
+ case "gemini":
954
+ return "GEMINI_API_KEY";
955
+ case "claude":
956
+ return "ANTHROPIC_API_KEY";
957
+ case "openai":
958
+ return "OPENAI_API_KEY";
959
+ }
960
+ }
961
+ async function analyzeImage(base64Image, config) {
962
+ const { provider } = config;
963
+ const apiKey = config.apiKey || getEnvVarForProvider(provider);
964
+ if (!apiKey) {
930
965
  return {
931
966
  success: false,
932
967
  description: "",
933
- provider: "gemini",
934
- error: message
968
+ provider,
969
+ error: `No API key found for ${provider} vision. Set ${getEnvVarName(provider)} environment variable.`
935
970
  };
936
971
  }
937
- }
938
- async function analyzeWithClaude(base64Image, apiKey, model = "claude-sonnet-4-20250514") {
972
+ console.log(`[Vision] Analyzing image with ${provider}...`);
939
973
  try {
940
- const Anthropic = (await import('@anthropic-ai/sdk')).default;
941
- const client = new Anthropic({ apiKey });
942
974
  const cleanBase64 = base64Image.replace(/^data:image\/\w+;base64,/, "");
943
- const response = await client.messages.create({
975
+ const model = getProviderModel(provider, apiKey, config.model);
976
+ const result = await ai.generateText({
944
977
  model,
945
- max_tokens: 1024,
978
+ maxTokens: 1024,
946
979
  messages: [
947
980
  {
948
981
  role: "user",
949
982
  content: [
950
983
  {
951
984
  type: "image",
952
- source: {
953
- type: "base64",
954
- media_type: "image/png",
955
- data: cleanBase64
956
- }
985
+ image: Buffer.from(cleanBase64, "base64"),
986
+ mimeType: "image/png"
957
987
  },
958
988
  {
959
989
  type: "text",
@@ -963,51 +993,24 @@ async function analyzeWithClaude(base64Image, apiKey, model = "claude-sonnet-4-2
963
993
  }
964
994
  ]
965
995
  });
966
- const textContent = response.content.find((c) => c.type === "text");
967
- const description = textContent && "text" in textContent ? textContent.text : "";
968
996
  return {
969
997
  success: true,
970
- description,
971
- provider: "claude"
998
+ description: result.text,
999
+ provider
972
1000
  };
973
1001
  } catch (error) {
974
1002
  const message = error instanceof Error ? error.message : String(error);
975
- console.error("[Vision] Claude analysis failed:", message);
976
- return {
977
- success: false,
978
- description: "",
979
- provider: "claude",
980
- error: message
981
- };
982
- }
983
- }
984
- async function analyzeImage(base64Image, config) {
985
- const { provider } = config;
986
- let apiKey = config.apiKey;
987
- if (!apiKey) {
988
- apiKey = provider === "gemini" ? process.env.GEMINI_API_KEY : process.env.ANTHROPIC_API_KEY;
989
- }
990
- if (!apiKey) {
1003
+ console.error(`[Vision] ${provider} analysis failed:`, message);
991
1004
  return {
992
1005
  success: false,
993
1006
  description: "",
994
1007
  provider,
995
- error: `No API key found for ${provider} vision. Set ${provider === "gemini" ? "GEMINI_API_KEY" : "ANTHROPIC_API_KEY"} environment variable.`
1008
+ error: message
996
1009
  };
997
1010
  }
998
- console.log(`[Vision] Analyzing image with ${provider}...`);
999
- if (provider === "gemini") {
1000
- return analyzeWithGemini(base64Image, apiKey, config.model);
1001
- } else {
1002
- return analyzeWithClaude(base64Image, apiKey, config.model);
1003
- }
1004
1011
  }
1005
1012
  function isVisionAvailable(provider) {
1006
- if (provider === "gemini") {
1007
- return !!process.env.GEMINI_API_KEY;
1008
- } else {
1009
- return !!process.env.ANTHROPIC_API_KEY;
1010
- }
1013
+ return !!getEnvVarForProvider(provider);
1011
1014
  }
1012
1015
 
1013
1016
  // src/server/annotation-store.ts
@@ -1251,9 +1254,14 @@ var handlers = {
1251
1254
  provider: requestProvider
1252
1255
  }
1253
1256
  });
1254
- if (isVisionAvailable("gemini")) {
1257
+ const visionProvider = msg.visionProvider || "gemini";
1258
+ const visionModel = msg.visionModel;
1259
+ const visionApiKey = msg.visionApiKey || (visionProvider === "gemini" ? process.env.GEMINI_API_KEY : visionProvider === "claude" ? process.env.ANTHROPIC_API_KEY : process.env.OPENAI_API_KEY);
1260
+ if (visionApiKey) {
1255
1261
  const visionResult = await analyzeImage(drawingAnnotation.drawingImage, {
1256
- provider: "gemini"
1262
+ provider: visionProvider,
1263
+ apiKey: visionApiKey,
1264
+ model: visionModel
1257
1265
  });
1258
1266
  if (visionResult.success) {
1259
1267
  visionDescription = visionResult.description;
@@ -1286,7 +1294,7 @@ ${visionDescription}`,
1286
1294
  type: "ai-event",
1287
1295
  event: {
1288
1296
  type: "text",
1289
- content: `[Vision not available - set GEMINI_API_KEY for image analysis]`,
1297
+ content: `[Vision not available - add your API key in Settings (gear icon)]`,
1290
1298
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1291
1299
  provider: requestProvider
1292
1300
  }
@@ -1297,6 +1305,8 @@ ${visionDescription}`,
1297
1305
  fastMode: msg.fastMode === true,
1298
1306
  visionDescription
1299
1307
  });
1308
+ console.log(`[Skema] Prompt:
1309
+ ${prompt}`);
1300
1310
  sendMessage(ws, {
1301
1311
  id: msg.id,
1302
1312
  type: "ai-event",
@@ -1327,7 +1337,14 @@ ${visionDescription}`,
1327
1337
  model: msg.model
1328
1338
  };
1329
1339
  const { process: aiProcess, events } = spawnAICLI(prompt, config);
1340
+ const prefixGreen = "\x1B[32m";
1341
+ const reset = "\x1B[0m";
1330
1342
  for await (const event of events) {
1343
+ if (event.type === "text" && event.content) {
1344
+ console.log(`${prefixGreen}[Skema ${requestProvider}]${reset} ${event.content}`);
1345
+ } else if (event.type === "error" && event.content) {
1346
+ console.error(`${prefixGreen}[Skema ${requestProvider}]${reset} ${event.content}`);
1347
+ }
1331
1348
  sendMessage(ws, {
1332
1349
  id: msg.id,
1333
1350
  type: "ai-event",
@@ -1720,6 +1737,7 @@ function startDaemon(config = {}) {
1720
1737
  exports.DELETE = DELETE;
1721
1738
  exports.IMAGE_ANALYSIS_PROMPT = IMAGE_ANALYSIS_PROMPT;
1722
1739
  exports.POST = POST;
1740
+ exports.VISION_MODELS = VISION_MODELS;
1723
1741
  exports.acknowledgeAnnotation = acknowledgeAnnotation;
1724
1742
  exports.analyzeImage = analyzeImage;
1725
1743
  exports.buildDetailedDomSelectionPrompt = buildDetailedDomSelectionPrompt;