@quilltap/plugin-utils 2.2.19 → 2.3.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/CHANGELOG.md +8 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +148 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +147 -24
- package/dist/index.mjs.map +1 -1
- package/dist/providers/index.d.mts +97 -1
- package/dist/providers/index.d.ts +97 -1
- package/dist/providers/index.js +147 -23
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/index.mjs +146 -23
- package/dist/providers/index.mjs.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to @quilltap/plugin-utils will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.3.0] - 2026-08-15
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `applyProfileParameters(body, params, allowlist, normalize?)` — the one mechanism providers use to forward a connection profile's free-form `parameters` blob onto a request body. Allow-listed (never spread, so `model` / `messages` / `stream` / `tools` stay unreachable from a profile); `undefined`, `null` and the empty string omit the key. Exported as a free function rather than a base-class method because only one plugin extends `OpenAICompatibleProvider` — Z.AI, OpenRouter and Ollama implement their providers directly and reach it by composition.
|
|
10
|
+
- `OpenAICompatibleProvider` gained `profileParamAllowlist` (empty by default, so every existing subclass is byte-identical on the wire until it opts in) and an overridable `normalizeProfileParam`, applied in both the streaming and non-streaming body builds.
|
|
11
|
+
- `OpenAICompatibleProvider` now sends `tools` / `tool_choice` when the caller supplies tools, and parses `tool_calls` back — from `choice.message.tool_calls` on the non-streaming path, and by accumulating index-keyed `delta.tool_calls` fragments while streaming. Previously it could never call a tool.
|
|
12
|
+
|
|
5
13
|
## [2.2.19] - 2026-08-03
|
|
6
14
|
|
|
7
15
|
### Fixed
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AnthropicToolDefinition, CharacterPluginDataEntry, CharacterPluginDataMap, GoogleToolDefinition, LogContext, LogLevel, OpenAIToolDefinition, PluginLogger, ToolCall, ToolCallRequest, ToolFormatOptions, ToolResult, UniversalTool, createConsoleLogger, createNoopLogger } from '@quilltap/plugin-types';
|
|
2
2
|
export { T as ToolCallFormat, a as ToolConvertTarget, b as applyDescriptionLimit, c as convertFromAnthropicFormat, d as convertFromGoogleFormat, e as convertOpenAIToAnthropicFormat, f as convertOpenAIToGoogleFormat, g as convertToAnthropicFormat, h as convertToGoogleFormat, i as convertToolTo, j as convertToolsTo, k as detectToolCallFormat, l as hasToolCalls, p as parseAnthropicToolCalls, m as parseGoogleToolCalls, n as parseOpenAIToolCalls, o as parseToolCalls } from './converters-BPYo8xdH.mjs';
|
|
3
3
|
export { PluginLoggerWithChild, __clearCoreLoggerFactory, __injectCoreLoggerFactory, createPluginLogger, getLogLevelFromEnv, hasCoreLogger } from './logging/index.mjs';
|
|
4
|
-
export { DEFAULT_REQUEST_TIMEOUT_MS, OpenAICompatibleProvider, OpenAICompatibleProviderConfig, buildRequestAbortSignal, buildSdkClientOptions, buildSdkRequestOptions, resolveRequestTimeoutMs } from './providers/index.mjs';
|
|
4
|
+
export { DEFAULT_REQUEST_TIMEOUT_MS, OpenAICompatibleProvider, OpenAICompatibleProviderConfig, ProfileParamNormalizer, applyProfileParameters, buildRequestAbortSignal, buildSdkClientOptions, buildSdkRequestOptions, resolveRequestTimeoutMs } from './providers/index.mjs';
|
|
5
5
|
export { CreateSystemPromptPluginOptions, createSystemPromptPlugin, validateSystemPromptPlugin } from './system-prompts/index.mjs';
|
|
6
6
|
export { isVMEnvironment, resolveHostGateway, rewriteLocalhostUrl } from './host-rewrite.mjs';
|
|
7
7
|
import 'openai';
|
|
@@ -124,6 +124,6 @@ declare function getQuilltapUserAgent(): string;
|
|
|
124
124
|
* Version of the plugin-utils package.
|
|
125
125
|
* Can be used at runtime to check compatibility.
|
|
126
126
|
*/
|
|
127
|
-
declare const PLUGIN_UTILS_VERSION = "2.
|
|
127
|
+
declare const PLUGIN_UTILS_VERSION = "2.3.0";
|
|
128
128
|
|
|
129
129
|
export { BUILTIN_TOOL_NAMES, PLUGIN_UTILS_VERSION, __clearQuilltapVersion, __injectQuilltapVersion, getBuiltinToolNames, getQuilltapUserAgent, getQuilltapVersion };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AnthropicToolDefinition, CharacterPluginDataEntry, CharacterPluginDataMap, GoogleToolDefinition, LogContext, LogLevel, OpenAIToolDefinition, PluginLogger, ToolCall, ToolCallRequest, ToolFormatOptions, ToolResult, UniversalTool, createConsoleLogger, createNoopLogger } from '@quilltap/plugin-types';
|
|
2
2
|
export { T as ToolCallFormat, a as ToolConvertTarget, b as applyDescriptionLimit, c as convertFromAnthropicFormat, d as convertFromGoogleFormat, e as convertOpenAIToAnthropicFormat, f as convertOpenAIToGoogleFormat, g as convertToAnthropicFormat, h as convertToGoogleFormat, i as convertToolTo, j as convertToolsTo, k as detectToolCallFormat, l as hasToolCalls, p as parseAnthropicToolCalls, m as parseGoogleToolCalls, n as parseOpenAIToolCalls, o as parseToolCalls } from './converters-BPYo8xdH.js';
|
|
3
3
|
export { PluginLoggerWithChild, __clearCoreLoggerFactory, __injectCoreLoggerFactory, createPluginLogger, getLogLevelFromEnv, hasCoreLogger } from './logging/index.js';
|
|
4
|
-
export { DEFAULT_REQUEST_TIMEOUT_MS, OpenAICompatibleProvider, OpenAICompatibleProviderConfig, buildRequestAbortSignal, buildSdkClientOptions, buildSdkRequestOptions, resolveRequestTimeoutMs } from './providers/index.js';
|
|
4
|
+
export { DEFAULT_REQUEST_TIMEOUT_MS, OpenAICompatibleProvider, OpenAICompatibleProviderConfig, ProfileParamNormalizer, applyProfileParameters, buildRequestAbortSignal, buildSdkClientOptions, buildSdkRequestOptions, resolveRequestTimeoutMs } from './providers/index.js';
|
|
5
5
|
export { CreateSystemPromptPluginOptions, createSystemPromptPlugin, validateSystemPromptPlugin } from './system-prompts/index.js';
|
|
6
6
|
export { isVMEnvironment, resolveHostGateway, rewriteLocalhostUrl } from './host-rewrite.js';
|
|
7
7
|
import 'openai';
|
|
@@ -124,6 +124,6 @@ declare function getQuilltapUserAgent(): string;
|
|
|
124
124
|
* Version of the plugin-utils package.
|
|
125
125
|
* Can be used at runtime to check compatibility.
|
|
126
126
|
*/
|
|
127
|
-
declare const PLUGIN_UTILS_VERSION = "2.
|
|
127
|
+
declare const PLUGIN_UTILS_VERSION = "2.3.0";
|
|
128
128
|
|
|
129
129
|
export { BUILTIN_TOOL_NAMES, PLUGIN_UTILS_VERSION, __clearQuilltapVersion, __injectQuilltapVersion, getBuiltinToolNames, getQuilltapUserAgent, getQuilltapVersion };
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ __export(src_exports, {
|
|
|
39
39
|
__injectCoreLoggerFactory: () => __injectCoreLoggerFactory,
|
|
40
40
|
__injectQuilltapVersion: () => __injectQuilltapVersion,
|
|
41
41
|
applyDescriptionLimit: () => applyDescriptionLimit,
|
|
42
|
+
applyProfileParameters: () => applyProfileParameters,
|
|
42
43
|
buildRequestAbortSignal: () => buildRequestAbortSignal,
|
|
43
44
|
buildSdkClientOptions: () => buildSdkClientOptions,
|
|
44
45
|
buildSdkRequestOptions: () => buildSdkRequestOptions,
|
|
@@ -427,6 +428,21 @@ function buildRequestAbortSignal(params, defaultMs = DEFAULT_REQUEST_TIMEOUT_MS)
|
|
|
427
428
|
return AbortSignal.timeout(resolveRequestTimeoutMs(params, defaultMs));
|
|
428
429
|
}
|
|
429
430
|
|
|
431
|
+
// src/providers/profile-parameters.ts
|
|
432
|
+
function applyProfileParameters(body, params, allowlist, normalize) {
|
|
433
|
+
const profile = params.profileParameters;
|
|
434
|
+
if (!profile || typeof profile !== "object") return;
|
|
435
|
+
const bag = profile;
|
|
436
|
+
for (const key of allowlist) {
|
|
437
|
+
const raw = bag[key];
|
|
438
|
+
if (raw === void 0 || raw === null) continue;
|
|
439
|
+
if (typeof raw === "string" && raw === "") continue;
|
|
440
|
+
const value = normalize ? normalize(key, raw, params, body) : raw;
|
|
441
|
+
if (value === void 0) continue;
|
|
442
|
+
body[key] = value;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
430
446
|
// src/providers/openai-compatible.ts
|
|
431
447
|
var DEFAULT_MAX_RETRIES = 2;
|
|
432
448
|
var OpenAICompatibleProvider = class {
|
|
@@ -442,6 +458,16 @@ var OpenAICompatibleProvider = class {
|
|
|
442
458
|
this.supportedMimeTypes = [];
|
|
443
459
|
/** Web search is not supported */
|
|
444
460
|
this.supportsWebSearch = false;
|
|
461
|
+
/**
|
|
462
|
+
* Profile-parameter keys this provider forwards from
|
|
463
|
+
* `LLMParams.profileParameters` onto the request body.
|
|
464
|
+
*
|
|
465
|
+
* **Empty by default**, so a subclass that declares nothing sends exactly the
|
|
466
|
+
* bytes it sent before this mechanism existed. Subclasses opt in by
|
|
467
|
+
* overriding with their own allow-list; `model`, `messages`, `stream`,
|
|
468
|
+
* `stream_options` and `tools` must never appear in one.
|
|
469
|
+
*/
|
|
470
|
+
this.profileParamAllowlist = [];
|
|
445
471
|
if (typeof config === "string") {
|
|
446
472
|
this.baseUrl = config;
|
|
447
473
|
this.providerName = "OpenAICompatible";
|
|
@@ -529,6 +555,53 @@ var OpenAICompatibleProvider = class {
|
|
|
529
555
|
buildRequestOptions(params) {
|
|
530
556
|
return buildSdkRequestOptions(params);
|
|
531
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* Per-key hook for allow-listed profile parameters. The default forwards the
|
|
560
|
+
* stored value verbatim.
|
|
561
|
+
*
|
|
562
|
+
* Override to reshape a value (the editor stores flat strings where some APIs
|
|
563
|
+
* want objects), to gate a key on the model, or — by writing into `body` and
|
|
564
|
+
* returning `undefined` — to send it under a different key entirely.
|
|
565
|
+
*/
|
|
566
|
+
normalizeProfileParam(_key, value, _params, _body) {
|
|
567
|
+
return value;
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Apply {@link profileParamAllowlist} to a request body under construction.
|
|
571
|
+
* Called by both body builds so the streaming and non-streaming shapes cannot
|
|
572
|
+
* drift apart.
|
|
573
|
+
*/
|
|
574
|
+
applyProfileParams(body, params) {
|
|
575
|
+
applyProfileParameters(
|
|
576
|
+
body,
|
|
577
|
+
params,
|
|
578
|
+
this.profileParamAllowlist,
|
|
579
|
+
(key, value, callParams, target) => this.normalizeProfileParam(key, value, callParams, target)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Normalize an OpenAI-shaped `tool_calls` array into Quilltap's `ToolCall`
|
|
584
|
+
* shape, tolerating servers that hand back already-parsed argument objects
|
|
585
|
+
* where the OpenAI wire format specifies a JSON string.
|
|
586
|
+
*/
|
|
587
|
+
normalizeToolCalls(toolCalls) {
|
|
588
|
+
if (!toolCalls || toolCalls.length === 0) return [];
|
|
589
|
+
const out = [];
|
|
590
|
+
for (const raw of toolCalls) {
|
|
591
|
+
const tc = raw;
|
|
592
|
+
if (!tc?.function?.name) continue;
|
|
593
|
+
const args = tc.function.arguments;
|
|
594
|
+
out.push({
|
|
595
|
+
id: tc.id ?? "",
|
|
596
|
+
type: "function",
|
|
597
|
+
function: {
|
|
598
|
+
name: tc.function.name,
|
|
599
|
+
arguments: typeof args === "string" ? args : JSON.stringify(args ?? {})
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
return out;
|
|
604
|
+
}
|
|
532
605
|
/**
|
|
533
606
|
* Sends a message and returns the complete response.
|
|
534
607
|
*
|
|
@@ -567,17 +640,26 @@ var OpenAICompatibleProvider = class {
|
|
|
567
640
|
content: m.content
|
|
568
641
|
};
|
|
569
642
|
});
|
|
643
|
+
const body = {
|
|
644
|
+
model: params.model,
|
|
645
|
+
messages,
|
|
646
|
+
temperature: params.temperature ?? 0.7,
|
|
647
|
+
max_tokens: params.maxTokens ?? 4096,
|
|
648
|
+
top_p: params.topP ?? 1,
|
|
649
|
+
stop: params.stop,
|
|
650
|
+
...params.cacheKey ? { user: params.cacheKey } : {},
|
|
651
|
+
// Tools arrive only once the runtime gate (the profile's "Allow tool
|
|
652
|
+
// use") has passed, so no separate guard is needed here.
|
|
653
|
+
...params.tools && params.tools.length > 0 ? { tools: params.tools, tool_choice: params.toolChoice ?? "auto" } : {}
|
|
654
|
+
};
|
|
655
|
+
this.applyProfileParams(body, params);
|
|
570
656
|
try {
|
|
571
|
-
const response = await client.chat.completions.create(
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
max_tokens: params.maxTokens ?? 4096,
|
|
576
|
-
top_p: params.topP ?? 1,
|
|
577
|
-
stop: params.stop,
|
|
578
|
-
...params.cacheKey ? { user: params.cacheKey } : {}
|
|
579
|
-
}, this.buildRequestOptions(params));
|
|
657
|
+
const response = await client.chat.completions.create(
|
|
658
|
+
body,
|
|
659
|
+
this.buildRequestOptions(params)
|
|
660
|
+
);
|
|
580
661
|
const choice = response.choices[0];
|
|
662
|
+
const toolCalls = this.normalizeToolCalls(choice.message.tool_calls);
|
|
581
663
|
return {
|
|
582
664
|
content: choice.message.content ?? "",
|
|
583
665
|
finishReason: choice.finish_reason,
|
|
@@ -587,7 +669,8 @@ var OpenAICompatibleProvider = class {
|
|
|
587
669
|
totalTokens: response.usage?.total_tokens ?? 0
|
|
588
670
|
},
|
|
589
671
|
raw: response,
|
|
590
|
-
attachmentResults
|
|
672
|
+
attachmentResults,
|
|
673
|
+
...toolCalls.length > 0 ? { toolCalls } : {}
|
|
591
674
|
};
|
|
592
675
|
} catch (error) {
|
|
593
676
|
this.logger.error(
|
|
@@ -636,23 +719,32 @@ var OpenAICompatibleProvider = class {
|
|
|
636
719
|
content: m.content
|
|
637
720
|
};
|
|
638
721
|
});
|
|
722
|
+
const body = {
|
|
723
|
+
model: params.model,
|
|
724
|
+
messages,
|
|
725
|
+
temperature: params.temperature ?? 0.7,
|
|
726
|
+
max_tokens: params.maxTokens ?? 4096,
|
|
727
|
+
top_p: params.topP ?? 1,
|
|
728
|
+
stop: params.stop,
|
|
729
|
+
stream: true,
|
|
730
|
+
stream_options: { include_usage: true },
|
|
731
|
+
...params.cacheKey ? { user: params.cacheKey } : {},
|
|
732
|
+
...params.tools && params.tools.length > 0 ? { tools: params.tools, tool_choice: params.toolChoice ?? "auto" } : {}
|
|
733
|
+
};
|
|
734
|
+
this.applyProfileParams(body, params);
|
|
639
735
|
try {
|
|
640
|
-
const stream = await client.chat.completions.create(
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
max_tokens: params.maxTokens ?? 4096,
|
|
645
|
-
top_p: params.topP ?? 1,
|
|
646
|
-
stop: params.stop,
|
|
647
|
-
stream: true,
|
|
648
|
-
stream_options: { include_usage: true },
|
|
649
|
-
...params.cacheKey ? { user: params.cacheKey } : {}
|
|
650
|
-
}, this.buildRequestOptions(params));
|
|
736
|
+
const stream = await client.chat.completions.create(
|
|
737
|
+
body,
|
|
738
|
+
this.buildRequestOptions(params)
|
|
739
|
+
);
|
|
651
740
|
let chunkCount = 0;
|
|
652
741
|
let accumulatedUsage = null;
|
|
742
|
+
const toolCallAccumulator = /* @__PURE__ */ new Map();
|
|
743
|
+
let finishReason = null;
|
|
653
744
|
for await (const chunk of stream) {
|
|
654
745
|
chunkCount++;
|
|
655
|
-
const
|
|
746
|
+
const choice = chunk.choices[0];
|
|
747
|
+
const content = choice?.delta?.content;
|
|
656
748
|
const hasUsage = chunk.usage;
|
|
657
749
|
if (hasUsage) {
|
|
658
750
|
accumulatedUsage = {
|
|
@@ -661,6 +753,17 @@ var OpenAICompatibleProvider = class {
|
|
|
661
753
|
total_tokens: chunk.usage?.total_tokens
|
|
662
754
|
};
|
|
663
755
|
}
|
|
756
|
+
if (choice?.delta?.tool_calls) {
|
|
757
|
+
for (const tcDelta of choice.delta.tool_calls) {
|
|
758
|
+
const idx = tcDelta.index ?? 0;
|
|
759
|
+
const existing = toolCallAccumulator.get(idx) ?? { id: "", name: "", arguments: "" };
|
|
760
|
+
if (tcDelta.id) existing.id = tcDelta.id;
|
|
761
|
+
if (tcDelta.function?.name) existing.name = tcDelta.function.name;
|
|
762
|
+
if (tcDelta.function?.arguments) existing.arguments += tcDelta.function.arguments;
|
|
763
|
+
toolCallAccumulator.set(idx, existing);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (choice?.finish_reason) finishReason = choice.finish_reason;
|
|
664
767
|
if (content) {
|
|
665
768
|
yield {
|
|
666
769
|
content,
|
|
@@ -668,6 +771,11 @@ var OpenAICompatibleProvider = class {
|
|
|
668
771
|
};
|
|
669
772
|
}
|
|
670
773
|
}
|
|
774
|
+
const toolCalls = Array.from(toolCallAccumulator.values()).filter((tc) => tc.name).map((tc) => ({
|
|
775
|
+
id: tc.id,
|
|
776
|
+
type: "function",
|
|
777
|
+
function: { name: tc.name, arguments: tc.arguments }
|
|
778
|
+
}));
|
|
671
779
|
yield {
|
|
672
780
|
content: "",
|
|
673
781
|
done: true,
|
|
@@ -676,7 +784,22 @@ var OpenAICompatibleProvider = class {
|
|
|
676
784
|
completionTokens: accumulatedUsage.completion_tokens ?? 0,
|
|
677
785
|
totalTokens: accumulatedUsage.total_tokens ?? 0
|
|
678
786
|
} : void 0,
|
|
679
|
-
attachmentResults
|
|
787
|
+
attachmentResults,
|
|
788
|
+
// Only synthesized when the stream actually carried tool calls: the
|
|
789
|
+
// host's tool detection reads `rawResponse`, and an empty one on every
|
|
790
|
+
// ordinary turn would be noise in the logs for no gain.
|
|
791
|
+
...toolCalls.length > 0 ? {
|
|
792
|
+
toolCalls,
|
|
793
|
+
rawResponse: {
|
|
794
|
+
choices: [
|
|
795
|
+
{
|
|
796
|
+
index: 0,
|
|
797
|
+
message: { role: "assistant", content: "", tool_calls: toolCalls },
|
|
798
|
+
finish_reason: finishReason
|
|
799
|
+
}
|
|
800
|
+
]
|
|
801
|
+
}
|
|
802
|
+
} : {}
|
|
680
803
|
};
|
|
681
804
|
} catch (error) {
|
|
682
805
|
this.logger.error(
|
|
@@ -977,7 +1100,7 @@ function rewriteLocalhostUrl(url) {
|
|
|
977
1100
|
}
|
|
978
1101
|
|
|
979
1102
|
// src/version.generated.ts
|
|
980
|
-
var PLUGIN_UTILS_VERSION = "2.
|
|
1103
|
+
var PLUGIN_UTILS_VERSION = "2.3.0";
|
|
981
1104
|
// Annotate the CommonJS export names for ESM import in node:
|
|
982
1105
|
0 && (module.exports = {
|
|
983
1106
|
BUILTIN_TOOL_NAMES,
|
|
@@ -989,6 +1112,7 @@ var PLUGIN_UTILS_VERSION = "2.2.19";
|
|
|
989
1112
|
__injectCoreLoggerFactory,
|
|
990
1113
|
__injectQuilltapVersion,
|
|
991
1114
|
applyDescriptionLimit,
|
|
1115
|
+
applyProfileParameters,
|
|
992
1116
|
buildRequestAbortSignal,
|
|
993
1117
|
buildSdkClientOptions,
|
|
994
1118
|
buildSdkRequestOptions,
|