iobroker.javascript 9.2.0 → 9.2.1
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/README.md +18 -9
- package/admin/assets/AiChatPanel-Cc1KscBJ.js +315 -0
- package/admin/assets/AiInlineProvider-DkgjVSFQ.js +7 -0
- package/admin/assets/ScriptEditor-6qrtvwPL.js +2 -0
- package/admin/assets/ScriptEditorVanillaMonaco-bJua4sm1.js +3 -0
- package/admin/assets/applyCodeEdit-BdRnbz2g.js +1 -0
- package/admin/assets/{index-DAkyON1r.js → index-BZxCaQhO.js} +1 -1
- package/admin/assets/{index-DW5CwIma.js → index-CYbVtccs.js} +132 -121
- package/admin/assets/index-CexrwGGC.js +986 -0
- package/admin/assets/{index-BI3JsAz_.js → index-DsW7vBcg.js} +1 -1
- package/admin/assets/inlineChatWidget-Cu6rb4Ar.js +2 -0
- package/admin/assets/inlineDiffController-DBLpPOe2.js +16 -0
- package/admin/assets/{localSharedImportMap-CqvxvyGG.js → localSharedImportMap-BCwqnmn4.js} +1 -1
- package/admin/assets/stateHoverProvider-CGChzV5W.js +3 -0
- package/admin/assets/{virtual_mf-REMOTE_ENTRY_ID_iobroker_javascript__remoteEntry_js-BJ03G6Pu.js → virtual_mf-REMOTE_ENTRY_ID_iobroker_javascript__remoteEntry_js-DNrEsMrg.js} +2 -2
- package/admin/custom/assets/{index-BVwMgafs.js → index-DNKzDki_.js} +152 -152
- package/admin/custom/assets/{index-DsIn9jH_.js → index-NItS-TWp.js} +1 -1
- package/admin/{assets/index-hwplVCgv.js → custom/assets/index-sozs10Ij.js} +45 -71
- package/admin/custom/assets/{localSharedImportMap-C4qXtGUd.js → localSharedImportMap-BxT0VwTO.js} +1 -1
- package/admin/custom/assets/{virtual_mf-REMOTE_ENTRY_ID_ConfigCustomJavascriptSet__customComponents_js-DFSXB0v2.js → virtual_mf-REMOTE_ENTRY_ID_ConfigCustomJavascriptSet__customComponents_js-Br3IlnqO.js} +2 -2
- package/admin/custom/customComponents.js +1 -1
- package/admin/jsonConfig.json +9 -9
- package/admin/mf-manifest.json +1 -1
- package/admin/remoteEntry.js +1 -1
- package/admin/tab.html +2 -2
- package/build/lib/aiProviderResolver.js +80 -0
- package/build/lib/aiProviderResolver.js.map +1 -0
- package/build/lib/anthropicAdapter.js +175 -0
- package/build/lib/anthropicAdapter.js.map +1 -0
- package/build/lib/sandbox.js +7 -2
- package/build/lib/sandbox.js.map +1 -1
- package/build/main.js +141 -107
- package/build/main.js.map +1 -1
- package/build/types.d.ts +1 -0
- package/docs/de/README.md +62 -4
- package/docs/en/README.md +62 -4
- package/io-package.json +68 -1
- package/package.json +1 -1
- package/admin/assets/AiChatPanel-sgt697A2.js +0 -296
- package/admin/assets/AiInlineProvider-Dd7eKxk4.js +0 -7
- package/admin/assets/ScriptEditor-CH4qJzqq.js +0 -2
- package/admin/assets/ScriptEditorVanillaMonaco-cB_90T0P.js +0 -1
- package/admin/custom/assets/index-CVIpIckw.js +0 -960
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Translation layer between OpenAI-style chat-completion messages/tools and
|
|
4
|
+
* Anthropic's native Messages API.
|
|
5
|
+
*
|
|
6
|
+
* The frontend (AiChatService / useAiChat) always speaks the OpenAI format:
|
|
7
|
+
* - tools[] = [{ type: 'function', function: { name, description, parameters } }]
|
|
8
|
+
* - assistant message with tool_calls[] = [{ id, type: 'function', function: { name, arguments } }]
|
|
9
|
+
* - tool-result message with { role: 'tool', tool_call_id, content }
|
|
10
|
+
* - response = { content, tool_calls? }
|
|
11
|
+
*
|
|
12
|
+
* Anthropic's API uses a different shape:
|
|
13
|
+
* - tools[] = [{ name, description, input_schema }]
|
|
14
|
+
* - assistant message content = [{ type: 'text', text }, { type: 'tool_use', id, name, input }]
|
|
15
|
+
* - tool-result = user message with content = [{ type: 'tool_result', tool_use_id, content }]
|
|
16
|
+
* - response body = { content: [text/tool_use blocks], stop_reason }
|
|
17
|
+
*
|
|
18
|
+
* These functions are pure so they can be unit-tested in isolation.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.translateToolsToAnthropic = translateToolsToAnthropic;
|
|
22
|
+
exports.translateMessagesToAnthropic = translateMessagesToAnthropic;
|
|
23
|
+
exports.translateAnthropicResponseToOpenAI = translateAnthropicResponseToOpenAI;
|
|
24
|
+
/** Translate OpenAI function-tool definitions to Anthropic tool definitions. */
|
|
25
|
+
function translateToolsToAnthropic(tools) {
|
|
26
|
+
if (!Array.isArray(tools)) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
const result = [];
|
|
30
|
+
for (const t of tools) {
|
|
31
|
+
// Only `function`-type tools are supported. Anthropic uses a flat shape.
|
|
32
|
+
const tool = t;
|
|
33
|
+
const fn = tool?.function;
|
|
34
|
+
if (!fn?.name) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
result.push({
|
|
38
|
+
name: fn.name,
|
|
39
|
+
description: fn.description,
|
|
40
|
+
// OpenAI's `parameters` and Anthropic's `input_schema` share the JSON Schema shape.
|
|
41
|
+
// If none is provided, Anthropic still requires an object schema.
|
|
42
|
+
input_schema: fn.parameters || { type: 'object', properties: {} },
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
/** Safe JSON.parse that returns an object on failure so we never throw mid-translation. */
|
|
48
|
+
function safeParseArgs(args) {
|
|
49
|
+
if (!args) {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(args);
|
|
54
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
55
|
+
return parsed;
|
|
56
|
+
}
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Translate a flat OpenAI-style message array into Anthropic's content-block format.
|
|
65
|
+
* System messages are extracted and returned separately (Anthropic takes `system`
|
|
66
|
+
* as a top-level request field, not an inline message).
|
|
67
|
+
*/
|
|
68
|
+
function translateMessagesToAnthropic(messages) {
|
|
69
|
+
if (!Array.isArray(messages)) {
|
|
70
|
+
return { system: '', messages: [] };
|
|
71
|
+
}
|
|
72
|
+
const systemChunks = [];
|
|
73
|
+
const out = [];
|
|
74
|
+
// Pending tool-results that must be grouped into a single `user` message per Anthropic's rules.
|
|
75
|
+
let pendingToolResults = [];
|
|
76
|
+
const flushToolResults = () => {
|
|
77
|
+
if (pendingToolResults.length) {
|
|
78
|
+
out.push({ role: 'user', content: pendingToolResults });
|
|
79
|
+
pendingToolResults = [];
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
for (const m of messages) {
|
|
83
|
+
if (!m || typeof m !== 'object') {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (m.role === 'system') {
|
|
87
|
+
if (typeof m.content === 'string' && m.content) {
|
|
88
|
+
systemChunks.push(m.content);
|
|
89
|
+
}
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (m.role === 'tool') {
|
|
93
|
+
// Tool results accumulate; they're flushed when the next non-tool message appears.
|
|
94
|
+
pendingToolResults.push({
|
|
95
|
+
type: 'tool_result',
|
|
96
|
+
tool_use_id: m.tool_call_id || '',
|
|
97
|
+
content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content ?? ''),
|
|
98
|
+
});
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
flushToolResults();
|
|
102
|
+
if (m.role === 'assistant') {
|
|
103
|
+
const blocks = [];
|
|
104
|
+
if (typeof m.content === 'string' && m.content) {
|
|
105
|
+
blocks.push({ type: 'text', text: m.content });
|
|
106
|
+
}
|
|
107
|
+
if (Array.isArray(m.tool_calls)) {
|
|
108
|
+
for (const tc of m.tool_calls) {
|
|
109
|
+
if (!tc?.id || !tc.function?.name) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
blocks.push({
|
|
113
|
+
type: 'tool_use',
|
|
114
|
+
id: tc.id,
|
|
115
|
+
name: tc.function.name,
|
|
116
|
+
input: safeParseArgs(tc.function.arguments),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Anthropic requires a non-empty content array for assistant messages.
|
|
121
|
+
if (blocks.length) {
|
|
122
|
+
out.push({ role: 'assistant', content: blocks });
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (m.role === 'user') {
|
|
127
|
+
// Plain text user message. Content blocks aren't needed here.
|
|
128
|
+
const text = typeof m.content === 'string' ? m.content : '';
|
|
129
|
+
if (text) {
|
|
130
|
+
out.push({ role: 'user', content: text });
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
flushToolResults();
|
|
136
|
+
return { system: systemChunks.join('\n\n'), messages: out };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Translate an Anthropic Messages API response back into the OpenAI-style
|
|
140
|
+
* `{ content, tool_calls }` shape that our frontend already understands.
|
|
141
|
+
*/
|
|
142
|
+
function translateAnthropicResponseToOpenAI(response) {
|
|
143
|
+
if (!response || !Array.isArray(response.content)) {
|
|
144
|
+
return { content: '' };
|
|
145
|
+
}
|
|
146
|
+
const textParts = [];
|
|
147
|
+
const toolCalls = [];
|
|
148
|
+
for (const block of response.content) {
|
|
149
|
+
if (!block || typeof block !== 'object') {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
153
|
+
textParts.push(block.text);
|
|
154
|
+
}
|
|
155
|
+
else if (block.type === 'tool_use') {
|
|
156
|
+
const tu = block;
|
|
157
|
+
toolCalls.push({
|
|
158
|
+
id: tu.id || '',
|
|
159
|
+
type: 'function',
|
|
160
|
+
function: {
|
|
161
|
+
name: tu.name || '',
|
|
162
|
+
arguments: JSON.stringify(tu.input ?? {}),
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const result = {
|
|
168
|
+
content: textParts.join('\n'),
|
|
169
|
+
};
|
|
170
|
+
if (toolCalls.length) {
|
|
171
|
+
result.tool_calls = toolCalls;
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=anthropicAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropicAdapter.js","sourceRoot":"","sources":["../../src/lib/anthropicAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Translation layer between OpenAI-style chat-completion messages/tools and\n * Anthropic's native Messages API.\n *\n * The frontend (AiChatService / useAiChat) always speaks the OpenAI format:\n * - tools[] = [{ type: 'function', function: { name, description, parameters } }]\n * - assistant message with tool_calls[] = [{ id, type: 'function', function: { name, arguments } }]\n * - tool-result message with { role: 'tool', tool_call_id, content }\n * - response = { content, tool_calls? }\n *\n * Anthropic's API uses a different shape:\n * - tools[] = [{ name, description, input_schema }]\n * - assistant message content = [{ type: 'text', text }, { type: 'tool_use', id, name, input }]\n * - tool-result = user message with content = [{ type: 'tool_result', tool_use_id, content }]\n * - response body = { content: [text/tool_use blocks], stop_reason }\n *\n * These functions are pure so they can be unit-tested in isolation.\n */\n\nexport interface OpenAITool {\n type: 'function';\n function: {\n name: string;\n description?: string;\n parameters?: unknown;\n };\n}\n\nexport interface AnthropicTool {\n name: string;\n description?: string;\n input_schema: unknown;\n}\n\nexport interface OpenAIToolCall {\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n}\n\nexport interface OpenAIMessage {\n role: 'system' | 'user' | 'assistant' | 'tool';\n content?: string | null;\n tool_calls?: OpenAIToolCall[];\n tool_call_id?: string;\n name?: string;\n}\n\ntype AnthropicContentBlock =\n | { type: 'text'; text: string }\n | { type: 'tool_use'; id: string; name: string; input: Record<string, unknown> }\n | { type: 'tool_result'; tool_use_id: string; content: string; is_error?: boolean };\n\nexport interface AnthropicMessage {\n role: 'user' | 'assistant';\n content: string | AnthropicContentBlock[];\n}\n\nexport interface AnthropicResponse {\n content?: AnthropicContentBlock[];\n stop_reason?: string;\n [key: string]: unknown;\n}\n\n/** Translate OpenAI function-tool definitions to Anthropic tool definitions. */\nexport function translateToolsToAnthropic(tools: unknown[] | undefined | null): AnthropicTool[] {\n if (!Array.isArray(tools)) {\n return [];\n }\n const result: AnthropicTool[] = [];\n for (const t of tools) {\n // Only `function`-type tools are supported. Anthropic uses a flat shape.\n const tool = t as OpenAITool;\n const fn = tool?.function;\n if (!fn?.name) {\n continue;\n }\n result.push({\n name: fn.name,\n description: fn.description,\n // OpenAI's `parameters` and Anthropic's `input_schema` share the JSON Schema shape.\n // If none is provided, Anthropic still requires an object schema.\n input_schema: fn.parameters || { type: 'object', properties: {} },\n });\n }\n return result;\n}\n\n/** Safe JSON.parse that returns an object on failure so we never throw mid-translation. */\nfunction safeParseArgs(args: string | undefined): Record<string, unknown> {\n if (!args) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(args);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n}\n\n/**\n * Translate a flat OpenAI-style message array into Anthropic's content-block format.\n * System messages are extracted and returned separately (Anthropic takes `system`\n * as a top-level request field, not an inline message).\n */\nexport function translateMessagesToAnthropic(messages: OpenAIMessage[] | undefined | null): {\n system: string;\n messages: AnthropicMessage[];\n} {\n if (!Array.isArray(messages)) {\n return { system: '', messages: [] };\n }\n\n const systemChunks: string[] = [];\n const out: AnthropicMessage[] = [];\n // Pending tool-results that must be grouped into a single `user` message per Anthropic's rules.\n let pendingToolResults: AnthropicContentBlock[] = [];\n\n const flushToolResults = (): void => {\n if (pendingToolResults.length) {\n out.push({ role: 'user', content: pendingToolResults });\n pendingToolResults = [];\n }\n };\n\n for (const m of messages) {\n if (!m || typeof m !== 'object') {\n continue;\n }\n\n if (m.role === 'system') {\n if (typeof m.content === 'string' && m.content) {\n systemChunks.push(m.content);\n }\n continue;\n }\n\n if (m.role === 'tool') {\n // Tool results accumulate; they're flushed when the next non-tool message appears.\n pendingToolResults.push({\n type: 'tool_result',\n tool_use_id: m.tool_call_id || '',\n content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content ?? ''),\n });\n continue;\n }\n\n flushToolResults();\n\n if (m.role === 'assistant') {\n const blocks: AnthropicContentBlock[] = [];\n if (typeof m.content === 'string' && m.content) {\n blocks.push({ type: 'text', text: m.content });\n }\n if (Array.isArray(m.tool_calls)) {\n for (const tc of m.tool_calls) {\n if (!tc?.id || !tc.function?.name) {\n continue;\n }\n blocks.push({\n type: 'tool_use',\n id: tc.id,\n name: tc.function.name,\n input: safeParseArgs(tc.function.arguments),\n });\n }\n }\n // Anthropic requires a non-empty content array for assistant messages.\n if (blocks.length) {\n out.push({ role: 'assistant', content: blocks });\n }\n continue;\n }\n\n if (m.role === 'user') {\n // Plain text user message. Content blocks aren't needed here.\n const text = typeof m.content === 'string' ? m.content : '';\n if (text) {\n out.push({ role: 'user', content: text });\n }\n continue;\n }\n }\n\n flushToolResults();\n\n return { system: systemChunks.join('\\n\\n'), messages: out };\n}\n\n/**\n * Translate an Anthropic Messages API response back into the OpenAI-style\n * `{ content, tool_calls }` shape that our frontend already understands.\n */\nexport function translateAnthropicResponseToOpenAI(response: AnthropicResponse | undefined | null): {\n content: string;\n tool_calls?: OpenAIToolCall[];\n} {\n if (!response || !Array.isArray(response.content)) {\n return { content: '' };\n }\n const textParts: string[] = [];\n const toolCalls: OpenAIToolCall[] = [];\n for (const block of response.content) {\n if (!block || typeof block !== 'object') {\n continue;\n }\n if (block.type === 'text' && typeof (block as { text?: unknown }).text === 'string') {\n textParts.push((block as { text: string }).text);\n } else if (block.type === 'tool_use') {\n const tu = block as { id?: string; name?: string; input?: unknown };\n toolCalls.push({\n id: tu.id || '',\n type: 'function',\n function: {\n name: tu.name || '',\n arguments: JSON.stringify(tu.input ?? {}),\n },\n });\n }\n }\n const result: { content: string; tool_calls?: OpenAIToolCall[] } = {\n content: textParts.join('\\n'),\n };\n if (toolCalls.length) {\n result.tool_calls = toolCalls;\n }\n return result;\n}\n"]}
|
package/build/lib/sandbox.js
CHANGED
|
@@ -2016,8 +2016,13 @@ function sandBox(script, name, verbose, debug, context) {
|
|
|
2016
2016
|
return true;
|
|
2017
2017
|
}
|
|
2018
2018
|
for (let i = 0; i < script.schedules.length; i++) {
|
|
2019
|
-
|
|
2020
|
-
|
|
2019
|
+
// Support both full IobSchedule objects (with nested _ioBroker) and
|
|
2020
|
+
// bare _ioBroker metadata objects as returned by getSchedules()
|
|
2021
|
+
const ioBrokerMeta = schedule && typeof schedule === 'object'
|
|
2022
|
+
? schedule._ioBroker || schedule
|
|
2023
|
+
: undefined;
|
|
2024
|
+
if (ioBrokerMeta?.type === 'cron') {
|
|
2025
|
+
if (script.schedules[i]._ioBroker.id === ioBrokerMeta.id) {
|
|
2021
2026
|
if (!mods.nodeSchedule.cancelJob(script.schedules[i])) {
|
|
2022
2027
|
sandbox.log('Error by canceling scheduled job', 'error');
|
|
2023
2028
|
}
|