Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gui-chat-plugin/set-image-style",
"version": "1.1.1",
"version": "2.0.0",
"description": "Set image style modifier plugin for GUIChat",
"type": "module",
"main": "./dist/index.cjs",
Expand Down Expand Up @@ -35,7 +35,7 @@
"test": "tsx --test tests/*.test.ts"
},
"peerDependencies": {
"gui-chat-protocol": "^1.2.0",
"gui-chat-protocol": "^2.0.0",
"vue": "^3.5.0"
},
"devDependencies": {
Expand All @@ -47,7 +47,7 @@
"eslint": "^10.8.0",
"eslint-plugin-vue": "^10.10.0",
"globals": "^17.8.0",
"gui-chat-protocol": "^1.2.0",
"gui-chat-protocol": "^2.0.0",
"tailwindcss": "^4.3.3",
"tsx": "^4.23.4",
"typescript": "~6.0.3",
Expand Down
14 changes: 14 additions & 0 deletions src/core/hostResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { ImageGenerationConfig } from "./types";

const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null;

const isOptionalString = (value: unknown): value is string | undefined =>
value === undefined || typeof value === "string";

export const isImageGenerationConfig = (
value: unknown,
): value is ImageGenerationConfig =>
isRecord(value) &&
typeof value["backend"] === "string" &&
isOptionalString(value["styleModifier"]);
22 changes: 15 additions & 7 deletions src/core/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
SetImageStyleJsonData,
ImageGenerationConfig,
} from "./types";
import { isImageGenerationConfig } from "./hostResponse";
import { TOOL_DEFINITION } from "./definition";

// Re-export for convenience
Expand All @@ -27,13 +28,9 @@ export const executeSetImageStyle = async (
): Promise<ToolResult<SetImageStyleData, SetImageStyleJsonData>> => {
const { styleModifier } = args;

// Check if app context provides image config functions
const app = context?.app as {
getImageConfig?: () => ImageGenerationConfig;
setConfig?: (key: string, value: ImageGenerationConfig) => void;
};
const app = context?.app;

if (!app?.getImageConfig) {
if (typeof app?.["getImageConfig"] !== "function") {
return {
message: "getImageConfig function not available",
jsonData: {
Expand All @@ -44,7 +41,18 @@ export const executeSetImageStyle = async (
}

try {
const config = app.getImageConfig();
const config = app["getImageConfig"]();

if (!isImageGenerationConfig(config)) {
return {
message: "getImageConfig returned an unrecognized config",
jsonData: {
success: false,
error: "getImageConfig returned an unrecognized config",
},
};
}

const previousStyleModifier = config.styleModifier || "";

// Update the config with new style modifier
Expand Down
44 changes: 44 additions & 0 deletions tests/hostResponse.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* `context.app.getImageConfig` returns `unknown` since gui-chat-protocol
* 2.0.0, so the plugin narrows it here instead of trusting the host's shape.
*
* Run with: yarn test
*/

import { test, describe } from "node:test";
import assert from "node:assert";
import { isImageGenerationConfig } from "../src/core/hostResponse.js";

describe("isImageGenerationConfig", () => {
test("accepts a config naming a backend", () => {
assert.equal(isImageGenerationConfig({ backend: "gemini" }), true);
});

test("accepts a config that already carries a style modifier", () => {
assert.equal(
isImageGenerationConfig({ backend: "gemini", styleModifier: "watercolor" }),
true,
);
});

test("rejects a config without a backend", () => {
assert.equal(isImageGenerationConfig({ styleModifier: "watercolor" }), false);
});

test("rejects a style modifier that is not a string", () => {
assert.equal(
isImageGenerationConfig({ backend: "gemini", styleModifier: 42 }),
false,
);
});

test("rejects values that are not a config object", () => {
[null, undefined, "ok", 7].forEach((value) => {
assert.equal(
isImageGenerationConfig(value),
false,
`should reject ${JSON.stringify(value)}`,
);
});
});
});
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1051,10 +1051,10 @@ graceful-fs@^4.2.4:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==

gui-chat-protocol@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/gui-chat-protocol/-/gui-chat-protocol-1.2.0.tgz#8bc7f8d4e31a625aff94fa2c79951b5b80c30145"
integrity sha512-5qKQCpXOrH5+QlOWujhYpsG469IB6nsSZ9TOoodsBQ+U5aAPGEEUbvmacyOmPsimHvsDLCxP0S/ZNycWEFHOww==
gui-chat-protocol@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/gui-chat-protocol/-/gui-chat-protocol-2.0.0.tgz#96f0f0a115c92f8567b68b9c74a53514e1f3253f"
integrity sha512-E02kPSXKH2bX4WAp6TuMjSx4Ftzr2n8XEQtPhZxRCKCBO9ss3Qkx4G5xWeZ6bVUCZtyhB+N8V8Jlv+YRPQJQ9w==

ignore@^5.2.0:
version "5.3.2"
Expand Down
Loading