@prestyj/ai 5.12.0 → 5.16.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/README.md +1 -1
- package/dist/index.cjs +37 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -1
- package/dist/index.d.ts +44 -1
- package/dist/index.js +36 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -3,6 +3,8 @@ import Anthropic from '@anthropic-ai/sdk';
|
|
|
3
3
|
import OpenAI from 'openai';
|
|
4
4
|
|
|
5
5
|
type Provider = "anthropic" | "xiaomi" | "openai" | "gemini" | "glm" | "moonshot" | "minimax" | "deepseek" | "openrouter" | "sakana" | "xai" | "palsu"
|
|
6
|
+
/** Hugging Face Inference Providers router (OpenAI-compatible). */
|
|
7
|
+
| "huggingface"
|
|
6
8
|
/** Locally hosted OpenAI-compatible server (Ollama, LM Studio, llama.cpp, vLLM). */
|
|
7
9
|
| "local";
|
|
8
10
|
type ThinkingLevel = "low" | "medium" | "high" | "xhigh" | "max" | "ultra";
|
|
@@ -530,6 +532,47 @@ type ProviderDiagnosticFn = (phase: string, data?: Record<string, unknown>) => v
|
|
|
530
532
|
/** Register a diagnostic callback for provider-level tracing. */
|
|
531
533
|
declare function setProviderDiagnostic(fn: ProviderDiagnosticFn | null): void;
|
|
532
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Converts a Zod schema to a JSON Schema object suitable for provider tool
|
|
537
|
+
* parameter definitions.
|
|
538
|
+
*
|
|
539
|
+
* Anthropic's `input_schema` validator is strict in two ways:
|
|
540
|
+
*
|
|
541
|
+
* 1. The root must be `type: "object"`. Returns 400 with
|
|
542
|
+
* `tools.N.custom.input_schema.type: Field required` otherwise.
|
|
543
|
+
*
|
|
544
|
+
* 2. The root must NOT contain `oneOf`, `anyOf`, or `allOf`. Returns 400 with
|
|
545
|
+
* `input_schema does not support oneOf, allOf, or anyOf at the top level`.
|
|
546
|
+
*
|
|
547
|
+
* Both rules trip whenever a tool's parameters are defined via
|
|
548
|
+
* `z.discriminatedUnion(...)` or `z.union(...)` — Zod 4's
|
|
549
|
+
* `z.toJSONSchema` emits `{oneOf: [...]}` at the root with no `type`.
|
|
550
|
+
*
|
|
551
|
+
* The fix is to collapse the union into a single flat object schema:
|
|
552
|
+
*
|
|
553
|
+
* - properties = union of all branch properties (later branches win on
|
|
554
|
+
* conflict; that's fine because the model only uses these for hints —
|
|
555
|
+
* Zod's actual `tool.parameters.parse(args)` is the real validator)
|
|
556
|
+
* - required = intersection of branch `required` arrays (a field is only
|
|
557
|
+
* required if EVERY branch requires it)
|
|
558
|
+
* - if the union has a discriminator field (every branch has the same
|
|
559
|
+
* property as a `const`), we replace the discriminator's per-branch
|
|
560
|
+
* `const` with an `enum` listing every literal — the model gets a clear
|
|
561
|
+
* hint of the valid action values without needing oneOf
|
|
562
|
+
*
|
|
563
|
+
* The flattening is lossy for *schema-level* constraints (e.g. "if action=X,
|
|
564
|
+
* then field Y is required") — Zod still enforces those at parse time. For
|
|
565
|
+
* the model's purposes this is identical to a single object with optional
|
|
566
|
+
* fields and a discriminator enum, which is exactly how Anthropic-supported
|
|
567
|
+
* tools are typically authored anyway.
|
|
568
|
+
*/
|
|
569
|
+
type JsonSchema = Record<string, unknown>;
|
|
570
|
+
/**
|
|
571
|
+
* Resolve a tool's JSON Schema for provider tool definitions: prefer the
|
|
572
|
+
* tool's pre-built `rawInputSchema`, otherwise convert its Zod `parameters`.
|
|
573
|
+
*/
|
|
574
|
+
declare function resolveToolSchema(tool: Tool): JsonSchema;
|
|
575
|
+
|
|
533
576
|
/**
|
|
534
577
|
* Cap historical images before provider dispatch, removing the oldest first.
|
|
535
578
|
* The persisted/live conversation is never mutated; only modified messages and
|
|
@@ -642,4 +685,4 @@ interface PalsuProviderConfig {
|
|
|
642
685
|
*/
|
|
643
686
|
declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
|
|
644
687
|
|
|
645
|
-
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
|
|
688
|
+
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import Anthropic from '@anthropic-ai/sdk';
|
|
|
3
3
|
import OpenAI from 'openai';
|
|
4
4
|
|
|
5
5
|
type Provider = "anthropic" | "xiaomi" | "openai" | "gemini" | "glm" | "moonshot" | "minimax" | "deepseek" | "openrouter" | "sakana" | "xai" | "palsu"
|
|
6
|
+
/** Hugging Face Inference Providers router (OpenAI-compatible). */
|
|
7
|
+
| "huggingface"
|
|
6
8
|
/** Locally hosted OpenAI-compatible server (Ollama, LM Studio, llama.cpp, vLLM). */
|
|
7
9
|
| "local";
|
|
8
10
|
type ThinkingLevel = "low" | "medium" | "high" | "xhigh" | "max" | "ultra";
|
|
@@ -530,6 +532,47 @@ type ProviderDiagnosticFn = (phase: string, data?: Record<string, unknown>) => v
|
|
|
530
532
|
/** Register a diagnostic callback for provider-level tracing. */
|
|
531
533
|
declare function setProviderDiagnostic(fn: ProviderDiagnosticFn | null): void;
|
|
532
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Converts a Zod schema to a JSON Schema object suitable for provider tool
|
|
537
|
+
* parameter definitions.
|
|
538
|
+
*
|
|
539
|
+
* Anthropic's `input_schema` validator is strict in two ways:
|
|
540
|
+
*
|
|
541
|
+
* 1. The root must be `type: "object"`. Returns 400 with
|
|
542
|
+
* `tools.N.custom.input_schema.type: Field required` otherwise.
|
|
543
|
+
*
|
|
544
|
+
* 2. The root must NOT contain `oneOf`, `anyOf`, or `allOf`. Returns 400 with
|
|
545
|
+
* `input_schema does not support oneOf, allOf, or anyOf at the top level`.
|
|
546
|
+
*
|
|
547
|
+
* Both rules trip whenever a tool's parameters are defined via
|
|
548
|
+
* `z.discriminatedUnion(...)` or `z.union(...)` — Zod 4's
|
|
549
|
+
* `z.toJSONSchema` emits `{oneOf: [...]}` at the root with no `type`.
|
|
550
|
+
*
|
|
551
|
+
* The fix is to collapse the union into a single flat object schema:
|
|
552
|
+
*
|
|
553
|
+
* - properties = union of all branch properties (later branches win on
|
|
554
|
+
* conflict; that's fine because the model only uses these for hints —
|
|
555
|
+
* Zod's actual `tool.parameters.parse(args)` is the real validator)
|
|
556
|
+
* - required = intersection of branch `required` arrays (a field is only
|
|
557
|
+
* required if EVERY branch requires it)
|
|
558
|
+
* - if the union has a discriminator field (every branch has the same
|
|
559
|
+
* property as a `const`), we replace the discriminator's per-branch
|
|
560
|
+
* `const` with an `enum` listing every literal — the model gets a clear
|
|
561
|
+
* hint of the valid action values without needing oneOf
|
|
562
|
+
*
|
|
563
|
+
* The flattening is lossy for *schema-level* constraints (e.g. "if action=X,
|
|
564
|
+
* then field Y is required") — Zod still enforces those at parse time. For
|
|
565
|
+
* the model's purposes this is identical to a single object with optional
|
|
566
|
+
* fields and a discriminator enum, which is exactly how Anthropic-supported
|
|
567
|
+
* tools are typically authored anyway.
|
|
568
|
+
*/
|
|
569
|
+
type JsonSchema = Record<string, unknown>;
|
|
570
|
+
/**
|
|
571
|
+
* Resolve a tool's JSON Schema for provider tool definitions: prefer the
|
|
572
|
+
* tool's pre-built `rawInputSchema`, otherwise convert its Zod `parameters`.
|
|
573
|
+
*/
|
|
574
|
+
declare function resolveToolSchema(tool: Tool): JsonSchema;
|
|
575
|
+
|
|
533
576
|
/**
|
|
534
577
|
* Cap historical images before provider dispatch, removing the oldest first.
|
|
535
578
|
* The persisted/live conversation is never mutated; only modified messages and
|
|
@@ -642,4 +685,4 @@ interface PalsuProviderConfig {
|
|
|
642
685
|
*/
|
|
643
686
|
declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
|
|
644
687
|
|
|
645
|
-
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
|
|
688
|
+
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ var PROVIDER_DISPLAY = {
|
|
|
59
59
|
openrouter: "OpenRouter",
|
|
60
60
|
sakana: "Sakana",
|
|
61
61
|
xai: "xAI (Grok)",
|
|
62
|
+
huggingface: "Hugging Face",
|
|
62
63
|
xiaomi: "Xiaomi (MiMo)",
|
|
63
64
|
minimax: "MiniMax"
|
|
64
65
|
};
|
|
@@ -126,7 +127,7 @@ function formatError(err) {
|
|
|
126
127
|
provider: err.provider,
|
|
127
128
|
statusCode: err.statusCode,
|
|
128
129
|
...err.requestId ? { requestId: err.requestId } : {},
|
|
129
|
-
guidance: "Request access via your Anthropic account team (see platform.claude.com/docs/en/about-claude/models/overview), or switch to Claude Fable 5 via the model selector \u2014 same underlying model, generally available."
|
|
130
|
+
guidance: "Request access via your Anthropic account team (see platform.claude.com/docs/en/about-claude/models/overview), or switch to Claude Fable 5.1 via the model selector \u2014 same underlying model, generally available."
|
|
130
131
|
};
|
|
131
132
|
}
|
|
132
133
|
if (isUsageLimitError(err)) {
|
|
@@ -1105,6 +1106,9 @@ function toLocalReasoningEffort(level) {
|
|
|
1105
1106
|
if (level === "max" || level === "ultra" || level === "xhigh") return "max";
|
|
1106
1107
|
return level;
|
|
1107
1108
|
}
|
|
1109
|
+
function toGlmReasoningEffort(level) {
|
|
1110
|
+
return level === "ultra" ? "max" : level;
|
|
1111
|
+
}
|
|
1108
1112
|
function toOpenAIReasoningEffort(level, model) {
|
|
1109
1113
|
const effort = level === "max" || level === "ultra" ? "xhigh" : level;
|
|
1110
1114
|
if (model.startsWith("fugu") && (effort === "low" || effort === "medium")) {
|
|
@@ -1551,7 +1555,15 @@ async function* runStream(options) {
|
|
|
1551
1555
|
yield keepalive;
|
|
1552
1556
|
break;
|
|
1553
1557
|
}
|
|
1554
|
-
// message_stop — loop exits naturally
|
|
1558
|
+
// message_stop — loop exits naturally.
|
|
1559
|
+
//
|
|
1560
|
+
// Deliberately NOT breaking early here. Breaking makes the SDK iterator
|
|
1561
|
+
// run `if (!done) controller.abort()` in its `finally`
|
|
1562
|
+
// (core/streaming.js:97), which tears the connection down instead of
|
|
1563
|
+
// returning it to the keep-alive pool — every turn would then pay a
|
|
1564
|
+
// fresh TLS handshake. Draining to the end is what every other Anthropic
|
|
1565
|
+
// client does, and the stall it guards against is handled by the agent
|
|
1566
|
+
// loop's idle timeout.
|
|
1555
1567
|
default:
|
|
1556
1568
|
yield keepalive;
|
|
1557
1569
|
break;
|
|
@@ -1974,6 +1986,11 @@ async function* runStream2(options) {
|
|
|
1974
1986
|
if (usesThinkingParam) {
|
|
1975
1987
|
if (options.thinking) {
|
|
1976
1988
|
params.thinking = { type: "enabled" };
|
|
1989
|
+
if (options.provider === "glm") {
|
|
1990
|
+
params.reasoning_effort = toGlmReasoningEffort(
|
|
1991
|
+
options.thinking
|
|
1992
|
+
);
|
|
1993
|
+
}
|
|
1977
1994
|
} else {
|
|
1978
1995
|
params.thinking = { type: "disabled" };
|
|
1979
1996
|
}
|
|
@@ -2956,6 +2973,7 @@ var CODE_ASSIST_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
|
|
|
2956
2973
|
"gemini-3.5-flash",
|
|
2957
2974
|
"gemini-3-flash",
|
|
2958
2975
|
"gemini-3.1-flash-lite",
|
|
2976
|
+
"gemini-3.7-flash",
|
|
2959
2977
|
"gemini-2.5-pro",
|
|
2960
2978
|
"gemini-2.5-flash",
|
|
2961
2979
|
"gemma-4-31b-it",
|
|
@@ -2978,13 +2996,14 @@ var ACCOUNT_GATED_MODELS = /* @__PURE__ */ new Set([
|
|
|
2978
2996
|
"gemini-3-flash",
|
|
2979
2997
|
"gemini-3.5-flash",
|
|
2980
2998
|
"gemini-3.1-pro-preview",
|
|
2981
|
-
"gemini-3.1-pro-preview-customtools"
|
|
2999
|
+
"gemini-3.1-pro-preview-customtools",
|
|
3000
|
+
"gemini-3.7-flash"
|
|
2982
3001
|
]);
|
|
2983
3002
|
function accountGatedMessage(model) {
|
|
2984
3003
|
return `Your Google account isn't entitled to "${model}" over Gemini Code Assist OAuth, so the API reports it as not found. This is an account-access limit, not a ezcoder bug.`;
|
|
2985
3004
|
}
|
|
2986
3005
|
function accountGatedHint() {
|
|
2987
|
-
return `Newer Gemini models (3.5 Flash, 3.1 Pro Preview) are available only to Code Assist Standard/Enterprise accounts with preview/GA access enabled by a cloud admin \u2014 free/personal accounts usually can't call them. Switch to Gemini 3.1 Flash Lite (it works on this account) with /model, or sign in with a Code Assist Standard/Enterprise account that has preview access.`;
|
|
3006
|
+
return `Newer Gemini models (3.7 Flash, 3.5 Flash, 3.1 Pro Preview) are available only to Code Assist Standard/Enterprise accounts with preview/GA access enabled by a cloud admin \u2014 free/personal accounts usually can't call them. Switch to Gemini 3.1 Flash Lite (it works on this account) with /model, or sign in with a Code Assist Standard/Enterprise account that has preview access.`;
|
|
2988
3007
|
}
|
|
2989
3008
|
function formatErrorMessage(status, body, model) {
|
|
2990
3009
|
if (status === 404 && !CODE_ASSIST_SUPPORTED_MODELS.has(model)) {
|
|
@@ -3668,6 +3687,18 @@ providerRegistry.register("openrouter", {
|
|
|
3668
3687
|
baseUrl: options.baseUrl ?? "https://openrouter.ai/api/v1"
|
|
3669
3688
|
})
|
|
3670
3689
|
});
|
|
3690
|
+
providerRegistry.register("huggingface", {
|
|
3691
|
+
// Hugging Face Inference Providers router — one HF token (hf.co/settings/tokens,
|
|
3692
|
+
// "Make calls to Inference Providers" permission) routes to whichever hosted
|
|
3693
|
+
// backend serves each open model. Chat Completions-compatible; model ids are
|
|
3694
|
+
// Hub repo paths ("Qwen/Qwen3-Coder-480B-A35B-Instruct"), optionally with an
|
|
3695
|
+
// ":auto"/":fastest"/":cheapest" provider-selection suffix. Billing follows
|
|
3696
|
+
// each backend's per-token rates on the HF account (small free tier).
|
|
3697
|
+
stream: (options) => streamOpenAI({
|
|
3698
|
+
...options,
|
|
3699
|
+
baseUrl: options.baseUrl ?? "https://router.huggingface.co/v1"
|
|
3700
|
+
})
|
|
3701
|
+
});
|
|
3671
3702
|
providerRegistry.register("sakana", {
|
|
3672
3703
|
// Sakana Fugu is a multi-agent system exposed as a standard LLM through the
|
|
3673
3704
|
// OpenAI-compatible Sakana API. We ride the Chat Completions transport (the
|
|
@@ -4162,6 +4193,7 @@ export {
|
|
|
4162
4193
|
redactText,
|
|
4163
4194
|
redactValue,
|
|
4164
4195
|
registerPalsuProvider,
|
|
4196
|
+
resolveToolSchema,
|
|
4165
4197
|
sanitizeMessagesForWire,
|
|
4166
4198
|
setProviderDiagnostic,
|
|
4167
4199
|
sliceHead,
|