@jxsuite/studio 0.32.0 → 0.33.0
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/studio.js +9694 -306
- package/dist/studio.js.map +105 -9
- package/package.json +10 -5
- package/src/panels/ai-panel.ts +388 -328
- package/src/platforms/devserver.ts +3 -47
- package/src/services/ai-settings.ts +107 -0
- package/src/services/ai-system-prompt.ts +617 -0
- package/src/services/ai-tools.ts +854 -0
- package/src/services/context-manager.ts +200 -0
- package/src/services/document-assistant.ts +183 -0
- package/src/services/jx-validate.ts +65 -0
- package/src/services/render-critic.ts +75 -0
- package/src/services/token-lint.ts +140 -0
- package/src/services/tool-executor.ts +156 -0
- package/src/state.ts +29 -0
- package/src/tabs/transact.ts +37 -1
- package/src/types.ts +2 -6
|
@@ -793,54 +793,10 @@ export function createDevServerPlatform() {
|
|
|
793
793
|
}
|
|
794
794
|
},
|
|
795
795
|
|
|
796
|
-
// ─── AI Assistant
|
|
796
|
+
// ─── AI Assistant (Stack B: OpenAI-compatible SSE proxy) ───────────────────
|
|
797
797
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
return await res.json();
|
|
801
|
-
},
|
|
802
|
-
|
|
803
|
-
/** @param {{ message: string; systemPrompt?: string }} opts */
|
|
804
|
-
async aiCreateSession(opts: { message: string; systemPrompt?: string }) {
|
|
805
|
-
const res = await fetch("/__studio/ai/session", {
|
|
806
|
-
body: JSON.stringify(opts),
|
|
807
|
-
headers: { "Content-Type": "application/json" },
|
|
808
|
-
method: "POST",
|
|
809
|
-
});
|
|
810
|
-
if (!res.ok) {
|
|
811
|
-
const body = await readJson<ErrorBody>(res);
|
|
812
|
-
throw new Error(body.error);
|
|
813
|
-
}
|
|
814
|
-
return await res.json();
|
|
815
|
-
},
|
|
816
|
-
|
|
817
|
-
/** @param {string} id @param {string} message */
|
|
818
|
-
async aiSendMessage(id: string, message: string) {
|
|
819
|
-
const res = await fetch(`/__studio/ai/session/${id}/message`, {
|
|
820
|
-
body: JSON.stringify({ message }),
|
|
821
|
-
headers: { "Content-Type": "application/json" },
|
|
822
|
-
method: "POST",
|
|
823
|
-
});
|
|
824
|
-
if (!res.ok) {
|
|
825
|
-
const body = await readJson<ErrorBody>(res);
|
|
826
|
-
throw new Error(body.error);
|
|
827
|
-
}
|
|
828
|
-
return await res.json();
|
|
829
|
-
},
|
|
830
|
-
|
|
831
|
-
/** @param {string} id */
|
|
832
|
-
aiStreamUrl(id: string) {
|
|
833
|
-
return `/__studio/ai/session/${id}/stream`;
|
|
834
|
-
},
|
|
835
|
-
|
|
836
|
-
/** @param {string} id */
|
|
837
|
-
async aiStopSession(id: string) {
|
|
838
|
-
await fetch(`/__studio/ai/session/${id}/stop`, { method: "POST" });
|
|
839
|
-
},
|
|
840
|
-
|
|
841
|
-
/** @param {string} id */
|
|
842
|
-
async aiDeleteSession(id: string) {
|
|
843
|
-
await fetch(`/__studio/ai/session/${id}`, { method: "DELETE" });
|
|
798
|
+
aiChatUrl() {
|
|
799
|
+
return "/__studio/ai/chat";
|
|
844
800
|
},
|
|
845
801
|
};
|
|
846
802
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* Ai-settings.js — local persistence for the AI assistant's provider settings.
|
|
4
|
+
*
|
|
5
|
+
* The Stack B proxy reads the OpenAI key from the `X-Api-Key` header (falling back to the server's
|
|
6
|
+
* `OPENAI_API_KEY` env var). Studio stores a user-supplied key in localStorage so the browser/dev
|
|
7
|
+
* build works without an env var. The key never leaves the machine except to the same-origin proxy.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const KEY_STORAGE = "jx.ai.openaiKey";
|
|
13
|
+
const BASE_URL_STORAGE = "jx.ai.baseUrl";
|
|
14
|
+
const MODEL_STORAGE = "jx.ai.model";
|
|
15
|
+
const DEFAULT_MODEL = "gpt-4o";
|
|
16
|
+
|
|
17
|
+
/** @returns {string} The stored OpenAI key, or "" if none/unavailable. */
|
|
18
|
+
export function getOpenAiKey() {
|
|
19
|
+
try {
|
|
20
|
+
return globalThis.localStorage?.getItem(KEY_STORAGE) ?? "";
|
|
21
|
+
} catch {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Persist (or clear) the OpenAI key.
|
|
28
|
+
*
|
|
29
|
+
* @param {string} key - The key to store; an empty/blank value clears it.
|
|
30
|
+
*/
|
|
31
|
+
export function setOpenAiKey(key: string) {
|
|
32
|
+
try {
|
|
33
|
+
const trimmed = (key || "").trim();
|
|
34
|
+
if (trimmed) {
|
|
35
|
+
globalThis.localStorage?.setItem(KEY_STORAGE, trimmed);
|
|
36
|
+
} else {
|
|
37
|
+
globalThis.localStorage?.removeItem(KEY_STORAGE);
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
/* LocalStorage unavailable — settings are not persisted. */
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** @returns {boolean} Whether a non-empty key is stored. */
|
|
45
|
+
export function hasOpenAiKey() {
|
|
46
|
+
return getOpenAiKey().length > 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @returns {string} The OpenAI-compatible base URL override (e.g. a local LLM, OpenRouter, Azure),
|
|
51
|
+
* or "" to use the proxy's default (`https://api.openai.com/v1` / server `OPENAI_BASE_URL`).
|
|
52
|
+
*/
|
|
53
|
+
export function getBaseUrl() {
|
|
54
|
+
try {
|
|
55
|
+
return globalThis.localStorage?.getItem(BASE_URL_STORAGE) ?? "";
|
|
56
|
+
} catch {
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Persist (or clear) the base URL override.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} url - The base URL; an empty/blank value clears the override.
|
|
65
|
+
*/
|
|
66
|
+
export function setBaseUrl(url: string) {
|
|
67
|
+
try {
|
|
68
|
+
const trimmed = (url || "").trim().replace(/\/+$/, "");
|
|
69
|
+
if (trimmed) {
|
|
70
|
+
globalThis.localStorage?.setItem(BASE_URL_STORAGE, trimmed);
|
|
71
|
+
} else {
|
|
72
|
+
globalThis.localStorage?.removeItem(BASE_URL_STORAGE);
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
/* LocalStorage unavailable — settings are not persisted. */
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── Model selection ────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/** @returns {string} The stored model ID, or the default ("gpt-4o"). */
|
|
82
|
+
export function getModel() {
|
|
83
|
+
try {
|
|
84
|
+
return globalThis.localStorage?.getItem(MODEL_STORAGE) || DEFAULT_MODEL;
|
|
85
|
+
} catch {
|
|
86
|
+
return DEFAULT_MODEL;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Persist the selected model ID.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} modelId - The model ID to store; an empty/blank value clears it, reverting to
|
|
94
|
+
* default.
|
|
95
|
+
*/
|
|
96
|
+
export function setModel(modelId: string) {
|
|
97
|
+
try {
|
|
98
|
+
const trimmed = (modelId || "").trim();
|
|
99
|
+
if (trimmed) {
|
|
100
|
+
globalThis.localStorage?.setItem(MODEL_STORAGE, trimmed);
|
|
101
|
+
} else {
|
|
102
|
+
globalThis.localStorage?.removeItem(MODEL_STORAGE);
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
/* LocalStorage unavailable — settings are not persisted. */
|
|
106
|
+
}
|
|
107
|
+
}
|