@aigne/aigne-hub 0.9.5 → 0.10.0-beta

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/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.0-beta](https://github.com/AIGNE-io/aigne-framework/compare/aigne-hub-v0.9.6...aigne-hub-v0.10.0-beta) (2025-09-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * improve image model architecture and file handling ([#527](https://github.com/AIGNE-io/aigne-framework/issues/527)) ([4db50aa](https://github.com/AIGNE-io/aigne-framework/commit/4db50aa0387a1a0f045ca11aaa61613e36ca7597))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @aigne/anthropic bumped to 0.13.5-beta
16
+ * @aigne/bedrock bumped to 0.10.5-beta
17
+ * @aigne/core bumped to 1.61.0-beta
18
+ * @aigne/deepseek bumped to 0.7.46-beta
19
+ * @aigne/doubao bumped to 1.1.0-beta
20
+ * @aigne/gemini bumped to 0.14.0-beta
21
+ * @aigne/ideogram bumped to 0.4.0-beta
22
+ * @aigne/ollama bumped to 0.7.46-beta
23
+ * @aigne/open-router bumped to 0.7.46-beta
24
+ * @aigne/openai bumped to 0.16.0-beta
25
+ * @aigne/platform-helpers bumped to 0.6.3-beta
26
+ * @aigne/poe bumped to 1.0.26-beta
27
+ * @aigne/transport bumped to 0.15.9-beta
28
+ * @aigne/xai bumped to 0.7.46-beta
29
+ * devDependencies
30
+ * @aigne/test-utils bumped to 0.5.53-beta
31
+
32
+ ## [0.9.6](https://github.com/AIGNE-io/aigne-framework/compare/aigne-hub-v0.9.5...aigne-hub-v0.9.6) (2025-09-18)
33
+
34
+
35
+ ### Dependencies
36
+
37
+ * The following workspace dependencies were updated
38
+ * dependencies
39
+ * @aigne/gemini bumped to 0.13.5
40
+
3
41
  ## [0.9.5](https://github.com/AIGNE-io/aigne-framework/compare/aigne-hub-v0.9.4...aigne-hub-v0.9.5) (2025-09-18)
4
42
 
5
43
 
@@ -9,7 +9,6 @@ const ufo_1 = require("ufo");
9
9
  const blocklet_js_1 = require("./utils/blocklet.js");
10
10
  const constants_js_1 = require("./utils/constants.js");
11
11
  const type_js_1 = require("./utils/type.js");
12
- const AIGNE_HUB_DEFAULT_IMAGE_MIME = "image/png";
13
12
  class AIGNEHubImageModel extends core_1.ImageModel {
14
13
  options;
15
14
  constructor(options) {
@@ -57,45 +56,14 @@ class AIGNEHubImageModel extends core_1.ImageModel {
57
56
  BLOCKLET_APP_PID ||
58
57
  ABT_NODE_DID ||
59
58
  `@aigne/aigne-hub:${typeof process !== "undefined" ? index_js_1.nodejs.os.hostname() : "unknown"}`;
60
- // Convert local image to base64
61
- if (input.image) {
62
- const images = Array.isArray(input.image) ? input.image : [input.image];
63
- input.image = await Promise.all(images.map(async (image) => {
64
- if (image.startsWith("http")) {
65
- try {
66
- const response = await this.downloadFile(image);
67
- const buffer = await response.arrayBuffer();
68
- const mime = response.headers.get("content-type") || AIGNE_HUB_DEFAULT_IMAGE_MIME;
69
- const base64 = Buffer.from(buffer).toString("base64");
70
- return `data:${mime};base64,${base64}`;
71
- }
72
- catch {
73
- return image;
74
- }
75
- }
76
- if (image.startsWith("file://")) {
77
- const filePath = image.replace("file://", "");
78
- if (index_js_1.nodejs.fsSync.existsSync(filePath)) {
79
- const mime = AIGNE_HUB_DEFAULT_IMAGE_MIME;
80
- const base64 = await index_js_1.nodejs.fs.readFile(filePath, "base64");
81
- return `data:${mime};base64,${base64}`;
82
- }
83
- throw new Error(`Local file not found: ${filePath}`);
84
- }
85
- if (index_js_1.nodejs.fsSync.existsSync(image)) {
86
- const mime = AIGNE_HUB_DEFAULT_IMAGE_MIME;
87
- const base64 = await index_js_1.nodejs.fs.readFile(image, "base64");
88
- return `data:${mime};base64,${base64}`;
89
- }
90
- return image;
91
- }));
92
- }
93
59
  const response = await (await this.client).__invoke(undefined, {
94
60
  ...input,
95
61
  modelOptions: {
96
62
  ...this.options.modelOptions,
97
63
  model: input.model || (await this.credential).model,
98
64
  },
65
+ // Shouldn't use `local` output type for remote AIGNE Hub call, client can not access the remote filesystem
66
+ outputType: core_1.FileOutputType.file,
99
67
  }, {
100
68
  ...options,
101
69
  streaming: false,
package/lib/cjs/index.js CHANGED
@@ -26,7 +26,15 @@ class AIGNEHubChatModel extends core_1.ChatModel {
26
26
  return new AIGNEHubChatModel(options);
27
27
  }
28
28
  constructor(options) {
29
- const provider = process.env.BLOCKLET_AIGNE_API_PROVIDER || AIGNEHubChatModel.name;
29
+ let provider = process.env.BLOCKLET_AIGNE_API_PROVIDER;
30
+ if (!provider && options.model) {
31
+ const parsed = (0, model_js_1.parseModel)(options.model);
32
+ if (parsed.provider && parsed.model) {
33
+ provider = parsed.provider;
34
+ options.model = parsed.model;
35
+ }
36
+ }
37
+ provider ||= AIGNEHubChatModel.name;
30
38
  const { match, all } = (0, model_js_1.findModel)(provider);
31
39
  if (!match) {
32
40
  const available = all.map((m) => m.name).join(", ");
@@ -52,7 +60,15 @@ class AIGNEHubImageModel extends core_1.ImageModel {
52
60
  return new AIGNEHubImageModel(options);
53
61
  }
54
62
  constructor(options) {
55
- const provider = process.env.BLOCKLET_AIGNE_API_PROVIDER || AIGNEHubImageModel.name;
63
+ let provider = process.env.BLOCKLET_AIGNE_API_PROVIDER;
64
+ if (!provider && options.model) {
65
+ const parsed = (0, model_js_1.parseModel)(options.model);
66
+ if (parsed.provider && parsed.model) {
67
+ provider = parsed.provider;
68
+ options.model = parsed.model;
69
+ }
70
+ }
71
+ provider ||= AIGNEHubImageModel.name;
56
72
  const { match, all } = (0, model_js_1.findImageModel)(provider);
57
73
  if (!match) {
58
74
  const available = all.map((m) => m.name).join(", ");
@@ -11,7 +11,7 @@ export interface LoadableModel {
11
11
  }
12
12
  export declare function availableModels(): LoadableModel[];
13
13
  export interface LoadableImageModel {
14
- name: string;
14
+ name: string | string[];
15
15
  apiKeyEnvName: string;
16
16
  create: (options: {
17
17
  apiKey?: string;
@@ -29,3 +29,7 @@ export declare function findImageModel(provider: string): {
29
29
  all: LoadableImageModel[];
30
30
  match: LoadableImageModel | undefined;
31
31
  };
32
+ export declare const parseModel: (model: string) => {
33
+ provider: string | undefined;
34
+ model: string | undefined;
35
+ };
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseModel = void 0;
3
4
  exports.availableModels = availableModels;
4
5
  exports.availableImageModels = availableImageModels;
5
6
  exports.findModel = findModel;
@@ -110,7 +111,7 @@ function availableImageModels() {
110
111
  create: (params) => new openai_1.OpenAIImageModel({ ...params, clientOptions }),
111
112
  },
112
113
  {
113
- name: gemini_1.GeminiImageModel.name,
114
+ name: [gemini_1.GeminiImageModel.name, "google"],
114
115
  apiKeyEnvName: "GEMINI_API_KEY",
115
116
  create: (params) => new gemini_1.GeminiImageModel({ ...params, clientOptions }),
116
117
  },
@@ -145,6 +146,17 @@ function findModel(provider) {
145
146
  function findImageModel(provider) {
146
147
  provider = provider.toLowerCase().replace(/-/g, "");
147
148
  const all = availableImageModels();
148
- const match = all.find((m) => m.name.toLowerCase().includes(provider));
149
+ const match = all.find((m) => {
150
+ if (typeof m.name === "string") {
151
+ return m.name.toLowerCase().includes(provider);
152
+ }
153
+ return m.name.some((n) => n.toLowerCase().includes(provider));
154
+ });
149
155
  return { all, match };
150
156
  }
157
+ const parseModel = (model) => {
158
+ model = model.replace(":", "/");
159
+ const { provider, name } = model.match(/(?<provider>[^/]*)(\/(?<name>.*))?/)?.groups ?? {};
160
+ return { provider: provider?.replace(/-/g, ""), model: name };
161
+ };
162
+ exports.parseModel = parseModel;
@@ -11,7 +11,7 @@ export interface LoadableModel {
11
11
  }
12
12
  export declare function availableModels(): LoadableModel[];
13
13
  export interface LoadableImageModel {
14
- name: string;
14
+ name: string | string[];
15
15
  apiKeyEnvName: string;
16
16
  create: (options: {
17
17
  apiKey?: string;
@@ -29,3 +29,7 @@ export declare function findImageModel(provider: string): {
29
29
  all: LoadableImageModel[];
30
30
  match: LoadableImageModel | undefined;
31
31
  };
32
+ export declare const parseModel: (model: string) => {
33
+ provider: string | undefined;
34
+ model: string | undefined;
35
+ };
@@ -1,4 +1,4 @@
1
- import { ImageModel, } from "@aigne/core";
1
+ import { FileOutputType, ImageModel, } from "@aigne/core";
2
2
  import { checkArguments } from "@aigne/core/utils/type-utils.js";
3
3
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
4
4
  import { BaseClient, } from "@aigne/transport/http-client/base-client.js";
@@ -6,7 +6,6 @@ import { joinURL } from "ufo";
6
6
  import { getAIGNEHubMountPoint } from "./utils/blocklet.js";
7
7
  import { AIGNE_HUB_BLOCKLET_DID, AIGNE_HUB_IMAGE_MODEL, AIGNE_HUB_URL } from "./utils/constants.js";
8
8
  import { aigneHubModelOptionsSchema } from "./utils/type.js";
9
- const AIGNE_HUB_DEFAULT_IMAGE_MIME = "image/png";
10
9
  export class AIGNEHubImageModel extends ImageModel {
11
10
  options;
12
11
  constructor(options) {
@@ -54,45 +53,14 @@ export class AIGNEHubImageModel extends ImageModel {
54
53
  BLOCKLET_APP_PID ||
55
54
  ABT_NODE_DID ||
56
55
  `@aigne/aigne-hub:${typeof process !== "undefined" ? nodejs.os.hostname() : "unknown"}`;
57
- // Convert local image to base64
58
- if (input.image) {
59
- const images = Array.isArray(input.image) ? input.image : [input.image];
60
- input.image = await Promise.all(images.map(async (image) => {
61
- if (image.startsWith("http")) {
62
- try {
63
- const response = await this.downloadFile(image);
64
- const buffer = await response.arrayBuffer();
65
- const mime = response.headers.get("content-type") || AIGNE_HUB_DEFAULT_IMAGE_MIME;
66
- const base64 = Buffer.from(buffer).toString("base64");
67
- return `data:${mime};base64,${base64}`;
68
- }
69
- catch {
70
- return image;
71
- }
72
- }
73
- if (image.startsWith("file://")) {
74
- const filePath = image.replace("file://", "");
75
- if (nodejs.fsSync.existsSync(filePath)) {
76
- const mime = AIGNE_HUB_DEFAULT_IMAGE_MIME;
77
- const base64 = await nodejs.fs.readFile(filePath, "base64");
78
- return `data:${mime};base64,${base64}`;
79
- }
80
- throw new Error(`Local file not found: ${filePath}`);
81
- }
82
- if (nodejs.fsSync.existsSync(image)) {
83
- const mime = AIGNE_HUB_DEFAULT_IMAGE_MIME;
84
- const base64 = await nodejs.fs.readFile(image, "base64");
85
- return `data:${mime};base64,${base64}`;
86
- }
87
- return image;
88
- }));
89
- }
90
56
  const response = await (await this.client).__invoke(undefined, {
91
57
  ...input,
92
58
  modelOptions: {
93
59
  ...this.options.modelOptions,
94
60
  model: input.model || (await this.credential).model,
95
61
  },
62
+ // Shouldn't use `local` output type for remote AIGNE Hub call, client can not access the remote filesystem
63
+ outputType: FileOutputType.file,
96
64
  }, {
97
65
  ...options,
98
66
  streaming: false,
package/lib/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ChatModel, ImageModel, } from "@aigne/core";
2
- import { findImageModel, findModel } from "./utils/model.js";
2
+ import { findImageModel, findModel, parseModel } from "./utils/model.js";
3
3
  export * from "./utils/blocklet.js";
4
4
  export * from "./utils/constants.js";
5
5
  export * from "./utils/model.js";
@@ -9,7 +9,15 @@ export class AIGNEHubChatModel extends ChatModel {
9
9
  return new AIGNEHubChatModel(options);
10
10
  }
11
11
  constructor(options) {
12
- const provider = process.env.BLOCKLET_AIGNE_API_PROVIDER || AIGNEHubChatModel.name;
12
+ let provider = process.env.BLOCKLET_AIGNE_API_PROVIDER;
13
+ if (!provider && options.model) {
14
+ const parsed = parseModel(options.model);
15
+ if (parsed.provider && parsed.model) {
16
+ provider = parsed.provider;
17
+ options.model = parsed.model;
18
+ }
19
+ }
20
+ provider ||= AIGNEHubChatModel.name;
13
21
  const { match, all } = findModel(provider);
14
22
  if (!match) {
15
23
  const available = all.map((m) => m.name).join(", ");
@@ -34,7 +42,15 @@ export class AIGNEHubImageModel extends ImageModel {
34
42
  return new AIGNEHubImageModel(options);
35
43
  }
36
44
  constructor(options) {
37
- const provider = process.env.BLOCKLET_AIGNE_API_PROVIDER || AIGNEHubImageModel.name;
45
+ let provider = process.env.BLOCKLET_AIGNE_API_PROVIDER;
46
+ if (!provider && options.model) {
47
+ const parsed = parseModel(options.model);
48
+ if (parsed.provider && parsed.model) {
49
+ provider = parsed.provider;
50
+ options.model = parsed.model;
51
+ }
52
+ }
53
+ provider ||= AIGNEHubImageModel.name;
38
54
  const { match, all } = findImageModel(provider);
39
55
  if (!match) {
40
56
  const available = all.map((m) => m.name).join(", ");
@@ -11,7 +11,7 @@ export interface LoadableModel {
11
11
  }
12
12
  export declare function availableModels(): LoadableModel[];
13
13
  export interface LoadableImageModel {
14
- name: string;
14
+ name: string | string[];
15
15
  apiKeyEnvName: string;
16
16
  create: (options: {
17
17
  apiKey?: string;
@@ -29,3 +29,7 @@ export declare function findImageModel(provider: string): {
29
29
  all: LoadableImageModel[];
30
30
  match: LoadableImageModel | undefined;
31
31
  };
32
+ export declare const parseModel: (model: string) => {
33
+ provider: string | undefined;
34
+ model: string | undefined;
35
+ };
@@ -104,7 +104,7 @@ export function availableImageModels() {
104
104
  create: (params) => new OpenAIImageModel({ ...params, clientOptions }),
105
105
  },
106
106
  {
107
- name: GeminiImageModel.name,
107
+ name: [GeminiImageModel.name, "google"],
108
108
  apiKeyEnvName: "GEMINI_API_KEY",
109
109
  create: (params) => new GeminiImageModel({ ...params, clientOptions }),
110
110
  },
@@ -139,6 +139,16 @@ export function findModel(provider) {
139
139
  export function findImageModel(provider) {
140
140
  provider = provider.toLowerCase().replace(/-/g, "");
141
141
  const all = availableImageModels();
142
- const match = all.find((m) => m.name.toLowerCase().includes(provider));
142
+ const match = all.find((m) => {
143
+ if (typeof m.name === "string") {
144
+ return m.name.toLowerCase().includes(provider);
145
+ }
146
+ return m.name.some((n) => n.toLowerCase().includes(provider));
147
+ });
143
148
  return { all, match };
144
149
  }
150
+ export const parseModel = (model) => {
151
+ model = model.replace(":", "/");
152
+ const { provider, name } = model.match(/(?<provider>[^/]*)(\/(?<name>.*))?/)?.groups ?? {};
153
+ return { provider: provider?.replace(/-/g, ""), model: name };
154
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/aigne-hub",
3
- "version": "0.9.5",
3
+ "version": "0.10.0-beta",
4
4
  "description": "AIGNE Hub SDK for integrating with Hub AI models",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -39,20 +39,20 @@
39
39
  "https-proxy-agent": "^7.0.6",
40
40
  "ufo": "^1.6.1",
41
41
  "zod": "^3.25.67",
42
- "@aigne/bedrock": "^0.10.4",
43
- "@aigne/core": "^1.60.3",
44
- "@aigne/deepseek": "^0.7.45",
45
- "@aigne/doubao": "^1.0.40",
46
- "@aigne/anthropic": "^0.13.4",
47
- "@aigne/ideogram": "^0.3.15",
48
- "@aigne/ollama": "^0.7.45",
49
- "@aigne/gemini": "^0.13.4",
50
- "@aigne/open-router": "^0.7.45",
51
- "@aigne/openai": "^0.15.4",
52
- "@aigne/poe": "^1.0.25",
53
- "@aigne/transport": "^0.15.8",
54
- "@aigne/xai": "^0.7.45",
55
- "@aigne/platform-helpers": "^0.6.2"
42
+ "@aigne/anthropic": "^0.13.5-beta",
43
+ "@aigne/core": "^1.61.0-beta",
44
+ "@aigne/bedrock": "^0.10.5-beta",
45
+ "@aigne/deepseek": "^0.7.46-beta",
46
+ "@aigne/doubao": "^1.1.0-beta",
47
+ "@aigne/gemini": "^0.14.0-beta",
48
+ "@aigne/ollama": "^0.7.46-beta",
49
+ "@aigne/ideogram": "^0.4.0-beta",
50
+ "@aigne/openai": "^0.16.0-beta",
51
+ "@aigne/open-router": "^0.7.46-beta",
52
+ "@aigne/platform-helpers": "^0.6.3-beta",
53
+ "@aigne/poe": "^1.0.26-beta",
54
+ "@aigne/xai": "^0.7.46-beta",
55
+ "@aigne/transport": "^0.15.9-beta"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/bun": "^1.2.22",
@@ -61,7 +61,7 @@
61
61
  "npm-run-all": "^4.1.5",
62
62
  "rimraf": "^6.0.1",
63
63
  "typescript": "^5.9.2",
64
- "@aigne/test-utils": "^0.5.52"
64
+ "@aigne/test-utils": "^0.5.53-beta"
65
65
  },
66
66
  "scripts": {
67
67
  "lint": "tsc --noEmit",