@fgv/ts-extras 5.1.0-44 → 5.1.0-46
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/packlets/ai-assist/apiClient.js +38 -14
- package/dist/packlets/ai-assist/apiClient.js.map +1 -1
- package/dist/packlets/ai-assist/index.js +2 -2
- package/dist/packlets/ai-assist/index.js.map +1 -1
- package/dist/packlets/ai-assist/jsonResponse.js +284 -10
- package/dist/packlets/ai-assist/jsonResponse.js.map +1 -1
- package/dist/packlets/ai-assist/model.js +108 -0
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/registry.js +75 -17
- package/dist/packlets/ai-assist/registry.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +17 -6
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +5 -5
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +4 -1
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +6 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +5 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +6 -1
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/dist/packlets/ai-assist/streamingClient.js +6 -6
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +65 -7
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -1
- package/dist/packlets/zip-file-tree/zipFileTreeWriter.js +16 -1
- package/dist/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -1
- package/dist/ts-extras.d.ts +396 -14
- package/lib/packlets/ai-assist/apiClient.d.ts +9 -0
- package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/apiClient.js +37 -13
- package/lib/packlets/ai-assist/apiClient.js.map +1 -1
- package/lib/packlets/ai-assist/index.d.ts +2 -2
- package/lib/packlets/ai-assist/index.d.ts.map +1 -1
- package/lib/packlets/ai-assist/index.js +7 -1
- package/lib/packlets/ai-assist/index.js.map +1 -1
- package/lib/packlets/ai-assist/jsonResponse.d.ts +103 -0
- package/lib/packlets/ai-assist/jsonResponse.d.ts.map +1 -1
- package/lib/packlets/ai-assist/jsonResponse.js +285 -10
- package/lib/packlets/ai-assist/jsonResponse.js.map +1 -1
- package/lib/packlets/ai-assist/model.d.ts +144 -1
- package/lib/packlets/ai-assist/model.d.ts.map +1 -1
- package/lib/packlets/ai-assist/model.js +112 -1
- package/lib/packlets/ai-assist/model.js.map +1 -1
- package/lib/packlets/ai-assist/registry.d.ts +26 -6
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
- package/lib/packlets/ai-assist/registry.js +75 -17
- package/lib/packlets/ai-assist/registry.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +17 -6
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +9 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +4 -4
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +9 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +4 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +6 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +5 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +6 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.js +5 -5
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +54 -6
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts.map +1 -1
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +65 -7
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts +26 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts.map +1 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.js +17 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,QAAQ,EACR,KAAK,iBAAiB,EACtB,oBAAoB,EACpB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,iCAAiC,EACtC,KAAK,iCAAiC,EACtC,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,KAAK,cAAc,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,SAAS,EACT,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC3B,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,KAAK,qBAAqB,EAC1B,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,EAC1B,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC/B,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,wBAAwB,EAC9B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,KAAK,+BAA+B,EACpC,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,KAAK,sCAAsC,EAC3C,KAAK,6BAA6B,EAClC,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,6BAA6B,EAClC,KAAK,6BAA6B,EAClC,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,6BAA6B,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
7
|
+
exports.extractJsonText = exports.classifyJsonParseFailure = exports.resolveEffectiveTools = exports.modelSpec = exports.modelSpecKey = exports.aiAssistSettings = exports.aiAssistProviderConfig = exports.aiToolEnablement = exports.aiClientToolConfig = exports.aiToolAnnotations = exports.aiServerToolConfig = exports.aiWebSearchToolConfig = exports.aiServerToolType = exports.aiProviderId = exports.executeClientToolTurn = exports.callProxiedCompletionStream = exports.callProviderCompletionStream = exports.callProxiedEmbedding = exports.callProviderEmbedding = exports.callProxiedListModels = exports.callProviderListModels = exports.callProxiedImageGeneration = exports.callProviderImageGeneration = exports.callProxiedCompletion = exports.callProviderCompletion = exports.DEFAULT_MODEL_CAPABILITY_CONFIG = exports.supportsEmbedding = exports.resolveEmbeddingCapability = exports.supportsImageGeneration = exports.resolveImageCapability = exports.getProviderDescriptor = exports.getProviderDescriptors = exports.allProviderIds = exports.validateResolvedOptions = exports.resolveImageOptions = exports.toDataUrl = exports.usesMaxCompletionTokensField = exports.isAdaptiveThinkingModel = exports.isResponsesOnlyModel = exports.resolveProviderModel = exports.resolveModelAlias = exports.MODEL_ALIAS_SIGIL = exports.resolveModel = exports.MODEL_SPEC_BASE_KEY = exports.allModelSpecKeys = exports.providerApiKeySecretName = exports.DEFAULT_AI_ASSIST = exports.DEFAULT_ANTHROPIC_MAX_TOKENS = exports.allModelCapabilities = exports.AiPrompt = void 0;
|
|
8
|
+
exports.anthropicEffortToBudgetTokens = exports.SMART_JSON_PROMPT_HINT = exports.generateJsonCompletion = exports.fencedStringifiedJson = void 0;
|
|
8
9
|
var model_1 = require("./model");
|
|
9
10
|
Object.defineProperty(exports, "AiPrompt", { enumerable: true, get: function () { return model_1.AiPrompt; } });
|
|
10
11
|
Object.defineProperty(exports, "allModelCapabilities", { enumerable: true, get: function () { return model_1.allModelCapabilities; } });
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_ANTHROPIC_MAX_TOKENS", { enumerable: true, get: function () { return model_1.DEFAULT_ANTHROPIC_MAX_TOKENS; } });
|
|
11
13
|
Object.defineProperty(exports, "DEFAULT_AI_ASSIST", { enumerable: true, get: function () { return model_1.DEFAULT_AI_ASSIST; } });
|
|
14
|
+
Object.defineProperty(exports, "providerApiKeySecretName", { enumerable: true, get: function () { return model_1.providerApiKeySecretName; } });
|
|
12
15
|
Object.defineProperty(exports, "allModelSpecKeys", { enumerable: true, get: function () { return model_1.allModelSpecKeys; } });
|
|
13
16
|
Object.defineProperty(exports, "MODEL_SPEC_BASE_KEY", { enumerable: true, get: function () { return model_1.MODEL_SPEC_BASE_KEY; } });
|
|
14
17
|
Object.defineProperty(exports, "resolveModel", { enumerable: true, get: function () { return model_1.resolveModel; } });
|
|
@@ -16,6 +19,8 @@ Object.defineProperty(exports, "MODEL_ALIAS_SIGIL", { enumerable: true, get: fun
|
|
|
16
19
|
Object.defineProperty(exports, "resolveModelAlias", { enumerable: true, get: function () { return model_1.resolveModelAlias; } });
|
|
17
20
|
Object.defineProperty(exports, "resolveProviderModel", { enumerable: true, get: function () { return model_1.resolveProviderModel; } });
|
|
18
21
|
Object.defineProperty(exports, "isResponsesOnlyModel", { enumerable: true, get: function () { return model_1.isResponsesOnlyModel; } });
|
|
22
|
+
Object.defineProperty(exports, "isAdaptiveThinkingModel", { enumerable: true, get: function () { return model_1.isAdaptiveThinkingModel; } });
|
|
23
|
+
Object.defineProperty(exports, "usesMaxCompletionTokensField", { enumerable: true, get: function () { return model_1.usesMaxCompletionTokensField; } });
|
|
19
24
|
Object.defineProperty(exports, "toDataUrl", { enumerable: true, get: function () { return model_1.toDataUrl; } });
|
|
20
25
|
var imageOptionsResolver_1 = require("./imageOptionsResolver");
|
|
21
26
|
Object.defineProperty(exports, "resolveImageOptions", { enumerable: true, get: function () { return imageOptionsResolver_1.resolveImageOptions; } });
|
|
@@ -58,6 +63,7 @@ Object.defineProperty(exports, "modelSpec", { enumerable: true, get: function ()
|
|
|
58
63
|
var toolFormats_1 = require("./toolFormats");
|
|
59
64
|
Object.defineProperty(exports, "resolveEffectiveTools", { enumerable: true, get: function () { return toolFormats_1.resolveEffectiveTools; } });
|
|
60
65
|
var jsonResponse_1 = require("./jsonResponse");
|
|
66
|
+
Object.defineProperty(exports, "classifyJsonParseFailure", { enumerable: true, get: function () { return jsonResponse_1.classifyJsonParseFailure; } });
|
|
61
67
|
Object.defineProperty(exports, "extractJsonText", { enumerable: true, get: function () { return jsonResponse_1.extractJsonText; } });
|
|
62
68
|
Object.defineProperty(exports, "fencedStringifiedJson", { enumerable: true, get: function () { return jsonResponse_1.fencedStringifiedJson; } });
|
|
63
69
|
var jsonCompletion_1 = require("./jsonCompletion");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/index.ts"],"names":[],"mappings":";AAAA;;;GAGG
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;AAEH,iCAiGiB;AAhGf,iGAAA,QAAQ,OAAA;AAER,6GAAA,oBAAoB,OAAA;AAcpB,qHAAA,4BAA4B,OAAA;AAe5B,0GAAA,iBAAiB,OAAA;AAEjB,iHAAA,wBAAwB,OAAA;AAoCxB,yGAAA,gBAAgB,OAAA;AAChB,4GAAA,mBAAmB,OAAA;AACnB,qGAAA,YAAY,OAAA;AAEZ,0GAAA,iBAAiB,OAAA;AACjB,0GAAA,iBAAiB,OAAA;AACjB,6GAAA,oBAAoB,OAAA;AACpB,6GAAA,oBAAoB,OAAA;AACpB,gHAAA,uBAAuB,OAAA;AACvB,qHAAA,4BAA4B,OAAA;AAC5B,kGAAA,SAAS,OAAA;AAmBX,+DAIgC;AAF9B,2HAAA,mBAAmB,OAAA;AACnB,+HAAA,uBAAuB,OAAA;AAGzB,uCASoB;AARlB,0GAAA,cAAc,OAAA;AACd,kHAAA,sBAAsB,OAAA;AACtB,iHAAA,qBAAqB,OAAA;AACrB,kHAAA,sBAAsB,OAAA;AACtB,mHAAA,uBAAuB,OAAA;AACvB,sHAAA,0BAA0B,OAAA;AAC1B,6GAAA,iBAAiB,OAAA;AACjB,2HAAA,+BAA+B,OAAA;AAGjC,yCAUqB;AATnB,mHAAA,sBAAsB,OAAA;AACtB,kHAAA,qBAAqB,OAAA;AACrB,wHAAA,2BAA2B,OAAA;AAC3B,uHAAA,0BAA0B,OAAA;AAC1B,mHAAA,sBAAsB,OAAA;AACtB,kHAAA,qBAAqB,OAAA;AAMvB,qDAI2B;AAHzB,wHAAA,qBAAqB,OAAA;AACrB,uHAAA,oBAAoB,OAAA;AAItB,qDAQ2B;AAPzB,+HAAA,4BAA4B,OAAA;AAC5B,8HAAA,2BAA2B,OAAA;AAE3B,wHAAA,qBAAqB,OAAA;AAMvB,2CAYsB;AAXpB,0GAAA,YAAY,OAAA;AACZ,8GAAA,gBAAgB,OAAA;AAChB,mHAAA,qBAAqB,OAAA;AACrB,gHAAA,kBAAkB,OAAA;AAClB,+GAAA,iBAAiB,OAAA;AACjB,gHAAA,kBAAkB,OAAA;AAClB,8GAAA,gBAAgB,OAAA;AAChB,oHAAA,sBAAsB,OAAA;AACtB,8GAAA,gBAAgB,OAAA;AAChB,0GAAA,YAAY,OAAA;AACZ,uGAAA,SAAS,OAAA;AAGX,6CAAsD;AAA7C,oHAAA,qBAAqB,OAAA;AAE9B,+CAQwB;AAPtB,wHAAA,wBAAwB,OAAA;AACxB,+GAAA,eAAe,OAAA;AACf,qHAAA,qBAAqB,OAAA;AAOvB,mDAM0B;AALxB,wHAAA,sBAAsB,OAAA;AACtB,wHAAA,sBAAsB,OAAA;AAMxB,qEAAwG;AAA/F,wIAAA,6BAA6B,OAAA","sourcesContent":["/**\n * AI assist packlet - provider registry, prompt class, settings, and API client.\n * @packageDocumentation\n */\n\nexport {\n AiPrompt,\n type AiModelCapability,\n allModelCapabilities,\n type AiProviderId,\n type AiServerToolType,\n type AiServerToolConfig,\n type AiToolConfig,\n type IAiWebSearchToolConfig,\n type IAiClientToolConfig,\n type IAiToolAnnotations,\n type IAiClientTool,\n type IAiClientToolCallSummary,\n type IAiClientToolContinuation,\n type IAiClientToolTurnResult,\n type IAiToolEnablement,\n type IAiCompletionResponse,\n DEFAULT_ANTHROPIC_MAX_TOKENS,\n type IChatMessage,\n type IChatRequest,\n type AiApiFormat,\n type AiImageApiFormat,\n type AiEmbeddingApiFormat,\n type AiEmbeddingTaskType,\n type IAiEmbeddingModelCapability,\n type IAiEmbeddingParams,\n type IAiEmbeddingUsage,\n type IAiEmbeddingResult,\n type IAiImageModelCapability,\n type IAiProviderDescriptor,\n type IAiAssistProviderConfig,\n type IAiAssistSettings,\n DEFAULT_AI_ASSIST,\n type IAiAssistKeyStore,\n providerApiKeySecretName,\n type IAiImageAttachment,\n type IAiImageData,\n type AiImageSize,\n type AiImageQuality,\n type GptImageSize,\n type GptImageQuality,\n type GptImageModelNames,\n type GrokImagineModelNames,\n type GeminiFlashImageModelNames,\n type IGptImageGenerationConfig,\n type IGrokImagineImageGenerationConfig,\n type IGeminiFlashImageGenerationConfig,\n type IGptImageModelOptions,\n type IGrokImagineModelOptions,\n type IGeminiFlashImageModelOptions,\n type IOtherModelOptions,\n type IModelFamilyConfig,\n type IAiImageGenerationOptions,\n type IAiImageGenerationParams,\n type IAiGeneratedImage,\n type IAiImageGenerationResponse,\n type IAiModelCapabilityRule,\n type IAiModelCapabilityConfig,\n type IAiModelInfo,\n type IAiStreamEvent,\n type IAiStreamTextDelta,\n type IAiStreamToolEvent,\n type IAiStreamToolUseStart,\n type IAiStreamToolUseDelta,\n type IAiStreamToolUseComplete,\n type IAiStreamDone,\n type IAiStreamError,\n type ModelSpec,\n type ModelSpecKey,\n type IModelSpecMap,\n allModelSpecKeys,\n MODEL_SPEC_BASE_KEY,\n resolveModel,\n type IModelAliasMap,\n MODEL_ALIAS_SIGIL,\n resolveModelAlias,\n resolveProviderModel,\n isResponsesOnlyModel,\n isAdaptiveThinkingModel,\n usesMaxCompletionTokensField,\n toDataUrl,\n type AiThinkingMode,\n type IThinkingConfig,\n type IThinkingProviderConfig,\n type IAnthropicThinkingOptions,\n type IOpenAiThinkingOptions,\n type IGeminiThinkingOptions,\n type IXAiThinkingOptions,\n type IOtherThinkingOptions,\n type IAnthropicThinkingConfig,\n type IOpenAiThinkingConfig,\n type IGeminiThinkingConfig,\n type IXAiThinkingConfig,\n type AnthropicThinkingModelNames,\n type OpenAiThinkingModelNames,\n type GeminiThinkingModelNames,\n type XAiThinkingModelNames\n} from './model';\n\nexport {\n type IResolvedImageOptions,\n resolveImageOptions,\n validateResolvedOptions\n} from './imageOptionsResolver';\n\nexport {\n allProviderIds,\n getProviderDescriptors,\n getProviderDescriptor,\n resolveImageCapability,\n supportsImageGeneration,\n resolveEmbeddingCapability,\n supportsEmbedding,\n DEFAULT_MODEL_CAPABILITY_CONFIG\n} from './registry';\n\nexport {\n callProviderCompletion,\n callProxiedCompletion,\n callProviderImageGeneration,\n callProxiedImageGeneration,\n callProviderListModels,\n callProxiedListModels,\n type IProviderCompletionParams,\n type IProviderImageGenerationParams,\n type IProviderListModelsParams\n} from './apiClient';\n\nexport {\n callProviderEmbedding,\n callProxiedEmbedding,\n type IProviderEmbeddingParams\n} from './embeddingClient';\n\nexport {\n callProviderCompletionStream,\n callProxiedCompletionStream,\n type IProviderCompletionStreamParams,\n executeClientToolTurn,\n type IExecuteClientToolTurnParams,\n type IExecuteClientToolTurnResult,\n type IToolExecutionDecision\n} from './streamingClient';\n\nexport {\n aiProviderId,\n aiServerToolType,\n aiWebSearchToolConfig,\n aiServerToolConfig,\n aiToolAnnotations,\n aiClientToolConfig,\n aiToolEnablement,\n aiAssistProviderConfig,\n aiAssistSettings,\n modelSpecKey,\n modelSpec\n} from './converters';\n\nexport { resolveEffectiveTools } from './toolFormats';\n\nexport {\n classifyJsonParseFailure,\n extractJsonText,\n fencedStringifiedJson,\n type IFencedStringifiedJsonExtractorOptions,\n type IFencedStringifiedJsonOptions,\n type JsonParseFailureReason,\n type JsonTextExtractor\n} from './jsonResponse';\n\nexport {\n generateJsonCompletion,\n SMART_JSON_PROMPT_HINT,\n type IGenerateJsonCompletionParams,\n type IGenerateJsonCompletionResult,\n type JsonPromptHint\n} from './jsonCompletion';\n\nexport { anthropicEffortToBudgetTokens, type IResolvedThinkingConfig } from './thinkingOptionsResolver';\n"]}
|
|
@@ -31,12 +31,115 @@ export type JsonTextExtractor = (text: string) => Result<string>;
|
|
|
31
31
|
*
|
|
32
32
|
* Out of scope: repairing malformed JSON, handling smart quotes, etc.
|
|
33
33
|
*
|
|
34
|
+
* When an object or array opens but never closes before the end of input —
|
|
35
|
+
* the shape a response truncated by a token cap leaves behind — the failure
|
|
36
|
+
* names that specifically (distinct from the generic "no JSON-shaped
|
|
37
|
+
* substring found" for input that never looked like JSON at all) and points
|
|
38
|
+
* at `IAiCompletionResponse.truncated` and the `maxTokens` request option as
|
|
39
|
+
* the likely cause and fix.
|
|
40
|
+
*
|
|
34
41
|
* @param text - Raw model output.
|
|
35
42
|
* @returns A `Result<string>` containing the JSON-shaped substring, or a
|
|
36
43
|
* `Failure` if no JSON-shaped substring was found.
|
|
37
44
|
* @public
|
|
38
45
|
*/
|
|
39
46
|
export declare const extractJsonText: JsonTextExtractor;
|
|
47
|
+
/**
|
|
48
|
+
* Typed reason a JSON-shaped LLM response failed to parse, so a caller can
|
|
49
|
+
* branch on the failure class instead of regex-matching the engine's
|
|
50
|
+
* `JSON.parse` message (whose wording varies across V8 / Node versions).
|
|
51
|
+
*
|
|
52
|
+
* Every classified arm describes a fault at an **object property-name
|
|
53
|
+
* position** — the position an LLM most often gets wrong, and the one whose
|
|
54
|
+
* repair strategy differs most by case:
|
|
55
|
+
*
|
|
56
|
+
* - `'unquoted-property-name'`: a bare identifier where a quoted name belongs
|
|
57
|
+
* (`{ key: 1 }`). `token` is the identifier run, `offset` its first
|
|
58
|
+
* character. Identifier recognition is ASCII-only, so a non-ASCII bare name
|
|
59
|
+
* (`{ ключ: 1 }`) reports `'unknown'` rather than being named.
|
|
60
|
+
* - `'single-quoted-property-name'`: a single-quoted name (`{ 'key': 1 }`).
|
|
61
|
+
* `token` is the quoted literal (or just `'` if it never closes), `offset`
|
|
62
|
+
* the opening quote.
|
|
63
|
+
* - `'unterminated-property-name'`: a name whose closing `"` is missing, and
|
|
64
|
+
* whose body swallowed structural text (`{ "key: 1 }`). `token` is the
|
|
65
|
+
* unterminated fragment, `offset` the opening quote.
|
|
66
|
+
* - `'elided-member'`: a `,` where a member is expected — a leading or doubled
|
|
67
|
+
* comma in an object (`{ , "a": 1 }`, `{ "a":1, , "b":2 }`) or an array
|
|
68
|
+
* (`[1, , 2]`). `token` is `','`, `offset` its position.
|
|
69
|
+
* - `'unknown'`: the catch-all. The scan reached the end of the text, or hit a
|
|
70
|
+
* fault it cannot name with confidence, and reports nothing rather than
|
|
71
|
+
* guessing. Truncated responses, missing colons, trailing commas, bad number
|
|
72
|
+
* literals, and anything else not listed above land here.
|
|
73
|
+
*
|
|
74
|
+
* `offset` is a 0-based index into the `text` passed to
|
|
75
|
+
* {@link AiAssist.classifyJsonParseFailure}, not into the extracted substring.
|
|
76
|
+
* @public
|
|
77
|
+
*/
|
|
78
|
+
export type JsonParseFailureReason = {
|
|
79
|
+
readonly kind: 'unquoted-property-name';
|
|
80
|
+
readonly token: string;
|
|
81
|
+
readonly offset: number;
|
|
82
|
+
} | {
|
|
83
|
+
readonly kind: 'single-quoted-property-name';
|
|
84
|
+
readonly token: string;
|
|
85
|
+
readonly offset: number;
|
|
86
|
+
} | {
|
|
87
|
+
readonly kind: 'unterminated-property-name';
|
|
88
|
+
readonly token: string;
|
|
89
|
+
readonly offset: number;
|
|
90
|
+
} | {
|
|
91
|
+
readonly kind: 'elided-member';
|
|
92
|
+
readonly token: string;
|
|
93
|
+
readonly offset: number;
|
|
94
|
+
} | {
|
|
95
|
+
readonly kind: 'unknown';
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Classifies why a JSON-shaped LLM response would not parse, returning a
|
|
99
|
+
* {@link AiAssist.JsonParseFailureReason} a caller can branch on — repair the
|
|
100
|
+
* cheap cases, re-prompt the expensive ones, fail outright on the rest —
|
|
101
|
+
* instead of regex-matching an engine-specific `JSON.parse` message.
|
|
102
|
+
*
|
|
103
|
+
* Pass the same raw model text you handed
|
|
104
|
+
* {@link AiAssist.fencedStringifiedJson} or {@link AiAssist.extractJsonText};
|
|
105
|
+
* this applies the same BOM / whitespace / fence / preamble handling before
|
|
106
|
+
* scanning, and reports `offset` against that original text.
|
|
107
|
+
*
|
|
108
|
+
* Classification is **structural and deliberately conservative**. The scan
|
|
109
|
+
* walks the JSON grammar itself rather than reading the engine's error string,
|
|
110
|
+
* so its verdicts are stable across Node versions — and any fault it cannot
|
|
111
|
+
* name with confidence comes back as `'unknown'` rather than a guess. In
|
|
112
|
+
* particular an input that opened a structure and never closed it (the
|
|
113
|
+
* truncated-response shape {@link AiAssist.extractJsonText} already diagnoses)
|
|
114
|
+
* classifies as `'unknown'` here; the two diagnostics are complementary, not
|
|
115
|
+
* competing.
|
|
116
|
+
*
|
|
117
|
+
* This never fails and never repairs — it only names the fault. It is a
|
|
118
|
+
* diagnostic on the failure path, so calling it on text that parses fine is
|
|
119
|
+
* harmless but pointless: it returns `'unknown'`.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```ts
|
|
123
|
+
* const parsed = fencedStringifiedJson({ inner }).convert(raw);
|
|
124
|
+
* if (parsed.isFailure()) {
|
|
125
|
+
* const reason = classifyJsonParseFailure(raw);
|
|
126
|
+
* switch (reason.kind) {
|
|
127
|
+
* case 'unquoted-property-name': // cheap to repair
|
|
128
|
+
* case 'single-quoted-property-name':
|
|
129
|
+
* break;
|
|
130
|
+
* case 'elided-member':
|
|
131
|
+
* case 'unterminated-property-name': // worth a re-prompt
|
|
132
|
+
* break;
|
|
133
|
+
* default: // 'unknown' — fail outright
|
|
134
|
+
* }
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @param text - Raw model output (the same string handed to the extractor).
|
|
139
|
+
* @returns A {@link AiAssist.JsonParseFailureReason}.
|
|
140
|
+
* @public
|
|
141
|
+
*/
|
|
142
|
+
export declare function classifyJsonParseFailure(text: string): JsonParseFailureReason;
|
|
40
143
|
/**
|
|
41
144
|
* Options shared by every {@link AiAssist.fencedStringifiedJson} call.
|
|
42
145
|
* @public
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonResponse.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/jsonResponse.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAc,KAAK,SAAS,EAAQ,MAAM,EAAW,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAErF;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"jsonResponse.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/jsonResponse.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAc,KAAK,SAAS,EAAQ,MAAM,EAAW,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAErF;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;AAgIjE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,eAAe,EAAE,iBAiC7B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5F;IAAE,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjG;IAAE,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChG;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAyMjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CAgB7E;AAED;;;GAGG;AACH,MAAM,WAAW,sCAAsC;IACrD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,iBAAiB,CAAC;CACxC;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B,CAAC,CAAC,CAAE,SAAQ,sCAAsC;IAC9F,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,sCAAsC,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;AAC9G;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,EAAE,6BAA6B,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
// SOFTWARE.
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
22
|
exports.extractJsonText = void 0;
|
|
23
|
+
exports.classifyJsonParseFailure = classifyJsonParseFailure;
|
|
23
24
|
exports.fencedStringifiedJson = fencedStringifiedJson;
|
|
24
25
|
/**
|
|
25
26
|
* JSON-tolerant extraction and converters for LLM responses.
|
|
@@ -37,7 +38,11 @@ exports.fencedStringifiedJson = fencedStringifiedJson;
|
|
|
37
38
|
*/
|
|
38
39
|
const ts_utils_1 = require("@fgv/ts-utils");
|
|
39
40
|
const ts_json_base_1 = require("@fgv/ts-json-base");
|
|
40
|
-
|
|
41
|
+
// Group 1 is the opening fence (marker, optional language tag, newline) and
|
|
42
|
+
// group 2 is the fenced body. Group 1 is captured only so a caller that needs
|
|
43
|
+
// to map a position inside the body back onto an offset in the original text
|
|
44
|
+
// can add its length instead of re-deriving the fence header.
|
|
45
|
+
const FENCED_BLOCK = /(```[A-Za-z0-9_-]*\s*\r?\n)([\s\S]*?)\r?\n?```/;
|
|
41
46
|
const BOM = /^\uFEFF/;
|
|
42
47
|
// Full RFC 8259 grammar so the extractor only succeeds when the entire
|
|
43
48
|
// candidate parses as a JSON primitive (instead of just starting like one).
|
|
@@ -92,11 +97,36 @@ function findBalancedJsonSubstring(text) {
|
|
|
92
97
|
else if (ch === close) {
|
|
93
98
|
depth--;
|
|
94
99
|
if (depth === 0) {
|
|
95
|
-
return text.slice(start, i + 1);
|
|
100
|
+
return { kind: 'found', value: text.slice(start, i + 1), start };
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
|
-
return
|
|
104
|
+
return start >= 0 ? { kind: 'unclosed', depth, start } : { kind: 'none' };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Strips the wrappers a model adds around JSON — byte-order mark, surrounding
|
|
108
|
+
* whitespace, Markdown code fence — and reports where what is left starts in
|
|
109
|
+
* the original text.
|
|
110
|
+
*
|
|
111
|
+
* Single source of truth for that step: {@link extractJsonText} and
|
|
112
|
+
* {@link classifyJsonParseFailure} must agree on what the candidate is, or a
|
|
113
|
+
* classified `offset` would point into text the extractor never parsed.
|
|
114
|
+
* @internal
|
|
115
|
+
*/
|
|
116
|
+
function locateJsonCandidate(text) {
|
|
117
|
+
const noBom = stripBom(text);
|
|
118
|
+
const stripped = noBom.trim();
|
|
119
|
+
const strippedBase = text.length - noBom.length + (noBom.length - noBom.trimStart().length);
|
|
120
|
+
const fenced = FENCED_BLOCK.exec(stripped);
|
|
121
|
+
if (fenced === null) {
|
|
122
|
+
return { stripped, text: stripped, base: strippedBase };
|
|
123
|
+
}
|
|
124
|
+
const body = fenced[2];
|
|
125
|
+
return {
|
|
126
|
+
stripped,
|
|
127
|
+
text: body.trim(),
|
|
128
|
+
base: strippedBase + fenced.index + fenced[1].length + (body.length - body.trimStart().length)
|
|
129
|
+
};
|
|
100
130
|
}
|
|
101
131
|
/**
|
|
102
132
|
* Default {@link AiAssist.JsonTextExtractor | extractor} for LLM responses. Tolerates:
|
|
@@ -108,6 +138,13 @@ function findBalancedJsonSubstring(text) {
|
|
|
108
138
|
*
|
|
109
139
|
* Out of scope: repairing malformed JSON, handling smart quotes, etc.
|
|
110
140
|
*
|
|
141
|
+
* When an object or array opens but never closes before the end of input —
|
|
142
|
+
* the shape a response truncated by a token cap leaves behind — the failure
|
|
143
|
+
* names that specifically (distinct from the generic "no JSON-shaped
|
|
144
|
+
* substring found" for input that never looked like JSON at all) and points
|
|
145
|
+
* at `IAiCompletionResponse.truncated` and the `maxTokens` request option as
|
|
146
|
+
* the likely cause and fix.
|
|
147
|
+
*
|
|
111
148
|
* @param text - Raw model output.
|
|
112
149
|
* @returns A `Result<string>` containing the JSON-shaped substring, or a
|
|
113
150
|
* `Failure` if no JSON-shaped substring was found.
|
|
@@ -117,12 +154,11 @@ const extractJsonText = (text) => {
|
|
|
117
154
|
if (typeof text !== 'string') {
|
|
118
155
|
return (0, ts_utils_1.fail)('extractJsonText: input must be a string.');
|
|
119
156
|
}
|
|
120
|
-
const
|
|
121
|
-
if (stripped.length === 0) {
|
|
157
|
+
const located = locateJsonCandidate(text);
|
|
158
|
+
if (located.stripped.length === 0) {
|
|
122
159
|
return (0, ts_utils_1.fail)('extractJsonText: input is empty.');
|
|
123
160
|
}
|
|
124
|
-
const
|
|
125
|
-
const candidate = fenced ? fenced[1].trim() : stripped;
|
|
161
|
+
const candidate = located.text;
|
|
126
162
|
if (candidate.length === 0) {
|
|
127
163
|
return (0, ts_utils_1.fail)('extractJsonText: no JSON content found.');
|
|
128
164
|
}
|
|
@@ -132,13 +168,252 @@ const extractJsonText = (text) => {
|
|
|
132
168
|
if (JSON_KEYWORD.test(candidate) || JSON_NUMBER.test(candidate) || JSON_STRING.test(candidate)) {
|
|
133
169
|
return (0, ts_utils_1.succeed)(candidate);
|
|
134
170
|
}
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
return (0, ts_utils_1.succeed)(
|
|
171
|
+
const scan = findBalancedJsonSubstring(candidate);
|
|
172
|
+
if (scan.kind === 'found') {
|
|
173
|
+
return (0, ts_utils_1.succeed)(scan.value);
|
|
174
|
+
}
|
|
175
|
+
if (scan.kind === 'unclosed') {
|
|
176
|
+
return (0, ts_utils_1.fail)(`extractJsonText: JSON structure opened but never closed (depth ${scan.depth} at end of input) — ` +
|
|
177
|
+
'response may have been truncated (check IAiCompletionResponse.truncated / raise maxTokens).');
|
|
138
178
|
}
|
|
139
179
|
return (0, ts_utils_1.fail)('extractJsonText: no JSON-shaped substring found.');
|
|
140
180
|
};
|
|
141
181
|
exports.extractJsonText = extractJsonText;
|
|
182
|
+
const UNKNOWN_PARSE_FAILURE = { kind: 'unknown' };
|
|
183
|
+
const JSON_WHITESPACE = /[ \t\n\r]/;
|
|
184
|
+
const IDENTIFIER_START = /[A-Za-z0-9_$]/;
|
|
185
|
+
const IDENTIFIER_PART = /[A-Za-z0-9_$.-]/;
|
|
186
|
+
// Characters that end an unquoted value run (`true`, `null`, a number, or
|
|
187
|
+
// garbage). Includes ':' so a stray colon at a value position produces an
|
|
188
|
+
// empty run — reported as 'unknown' — instead of being swallowed by a literal.
|
|
189
|
+
const VALUE_RUN_TERMINATOR = /[\s,}\]:"'{[]/;
|
|
190
|
+
function scanQuotedRun(text, start, quote) {
|
|
191
|
+
let escape = false;
|
|
192
|
+
for (let i = start + 1; i < text.length; i++) {
|
|
193
|
+
const ch = text.charAt(i);
|
|
194
|
+
if (escape) {
|
|
195
|
+
escape = false;
|
|
196
|
+
}
|
|
197
|
+
else if (ch === '\\') {
|
|
198
|
+
escape = true;
|
|
199
|
+
}
|
|
200
|
+
else if (ch === quote) {
|
|
201
|
+
return { terminated: true, end: i + 1, body: text.slice(start + 1, i) };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { terminated: false, end: text.length, body: text.slice(start + 1) };
|
|
205
|
+
}
|
|
206
|
+
function skipJsonWhitespace(text, from) {
|
|
207
|
+
let i = from;
|
|
208
|
+
while (i < text.length && JSON_WHITESPACE.test(text.charAt(i))) {
|
|
209
|
+
i++;
|
|
210
|
+
}
|
|
211
|
+
return i;
|
|
212
|
+
}
|
|
213
|
+
function scanRun(text, from, isPart) {
|
|
214
|
+
let i = from;
|
|
215
|
+
while (i < text.length && isPart(text.charAt(i))) {
|
|
216
|
+
i++;
|
|
217
|
+
}
|
|
218
|
+
return text.slice(from, i);
|
|
219
|
+
}
|
|
220
|
+
function classifyAtPropertyName(text, i, base) {
|
|
221
|
+
const ch = text.charAt(i);
|
|
222
|
+
if (ch === '"') {
|
|
223
|
+
const scan = scanQuotedRun(text, i, '"');
|
|
224
|
+
if (scan.terminated) {
|
|
225
|
+
return { next: scan.end };
|
|
226
|
+
}
|
|
227
|
+
// An unterminated name is only distinguishable from a mid-name truncation
|
|
228
|
+
// when the swallowed body contains structural text — a ':' the author
|
|
229
|
+
// plainly meant as the name/value separator. Without that, stay honest.
|
|
230
|
+
return scan.body.includes(':')
|
|
231
|
+
? { reason: { kind: 'unterminated-property-name', token: text.slice(i), offset: base + i } }
|
|
232
|
+
: { reason: UNKNOWN_PARSE_FAILURE };
|
|
233
|
+
}
|
|
234
|
+
if (ch === "'") {
|
|
235
|
+
const scan = scanQuotedRun(text, i, "'");
|
|
236
|
+
return {
|
|
237
|
+
reason: {
|
|
238
|
+
kind: 'single-quoted-property-name',
|
|
239
|
+
token: scan.terminated ? text.slice(i, scan.end) : "'",
|
|
240
|
+
offset: base + i
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
if (ch === ',') {
|
|
245
|
+
return { reason: { kind: 'elided-member', token: ',', offset: base + i } };
|
|
246
|
+
}
|
|
247
|
+
if (IDENTIFIER_START.test(ch)) {
|
|
248
|
+
return {
|
|
249
|
+
reason: {
|
|
250
|
+
kind: 'unquoted-property-name',
|
|
251
|
+
token: scanRun(text, i, (c) => IDENTIFIER_PART.test(c)),
|
|
252
|
+
offset: base + i
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
return { reason: UNKNOWN_PARSE_FAILURE };
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Walks `text` from `from` (the opening `{` or `[`) as a permissive JSON
|
|
260
|
+
* scanner, reporting the first fault it can name with confidence. Anything it
|
|
261
|
+
* cannot name — including a document that scans clean — yields `'unknown'`.
|
|
262
|
+
*
|
|
263
|
+
* The scan is structural: it never reads the engine's `JSON.parse` message, so
|
|
264
|
+
* its verdicts do not drift with the Node version.
|
|
265
|
+
* @internal
|
|
266
|
+
*/
|
|
267
|
+
function scanForParseFailure(text, from, base) {
|
|
268
|
+
const stack = [];
|
|
269
|
+
let expect = 'value';
|
|
270
|
+
let i = from;
|
|
271
|
+
for (;;) {
|
|
272
|
+
i = skipJsonWhitespace(text, i);
|
|
273
|
+
if (i >= text.length) {
|
|
274
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
275
|
+
}
|
|
276
|
+
const ch = text.charAt(i);
|
|
277
|
+
const top = stack[stack.length - 1];
|
|
278
|
+
if (expect === 'name') {
|
|
279
|
+
if (ch === '}') {
|
|
280
|
+
stack.pop();
|
|
281
|
+
i++;
|
|
282
|
+
expect = 'comma';
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const outcome = classifyAtPropertyName(text, i, base);
|
|
286
|
+
if ('reason' in outcome) {
|
|
287
|
+
return outcome.reason;
|
|
288
|
+
}
|
|
289
|
+
i = outcome.next;
|
|
290
|
+
expect = 'colon';
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (expect === 'colon') {
|
|
294
|
+
if (ch !== ':') {
|
|
295
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
296
|
+
}
|
|
297
|
+
i++;
|
|
298
|
+
expect = 'value';
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (expect === 'value') {
|
|
302
|
+
if (ch === '{' || ch === '[') {
|
|
303
|
+
stack.push(ch === '{' ? 'object' : 'array');
|
|
304
|
+
i++;
|
|
305
|
+
expect = ch === '{' ? 'name' : 'value';
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (ch === ']' && top === 'array') {
|
|
309
|
+
stack.pop();
|
|
310
|
+
i++;
|
|
311
|
+
expect = 'comma';
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (ch === ',') {
|
|
315
|
+
return top === 'array'
|
|
316
|
+
? { kind: 'elided-member', token: ',', offset: base + i }
|
|
317
|
+
: UNKNOWN_PARSE_FAILURE;
|
|
318
|
+
}
|
|
319
|
+
if (ch === '"') {
|
|
320
|
+
const scan = scanQuotedRun(text, i, '"');
|
|
321
|
+
if (!scan.terminated) {
|
|
322
|
+
// Could equally be a truncated value; the extractor already names
|
|
323
|
+
// truncation, so do not compete with it here.
|
|
324
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
325
|
+
}
|
|
326
|
+
i = scan.end;
|
|
327
|
+
expect = 'comma';
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
const literal = scanRun(text, i, (c) => !VALUE_RUN_TERMINATOR.test(c));
|
|
331
|
+
if (literal.length === 0) {
|
|
332
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
333
|
+
}
|
|
334
|
+
i += literal.length;
|
|
335
|
+
expect = 'comma';
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
// expect === 'comma': a complete value just closed.
|
|
339
|
+
if (top === undefined) {
|
|
340
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
341
|
+
}
|
|
342
|
+
if (ch === ',') {
|
|
343
|
+
i++;
|
|
344
|
+
expect = top === 'object' ? 'name' : 'value';
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if ((ch === '}' && top === 'object') || (ch === ']' && top === 'array')) {
|
|
348
|
+
stack.pop();
|
|
349
|
+
i++;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Classifies why a JSON-shaped LLM response would not parse, returning a
|
|
357
|
+
* {@link AiAssist.JsonParseFailureReason} a caller can branch on — repair the
|
|
358
|
+
* cheap cases, re-prompt the expensive ones, fail outright on the rest —
|
|
359
|
+
* instead of regex-matching an engine-specific `JSON.parse` message.
|
|
360
|
+
*
|
|
361
|
+
* Pass the same raw model text you handed
|
|
362
|
+
* {@link AiAssist.fencedStringifiedJson} or {@link AiAssist.extractJsonText};
|
|
363
|
+
* this applies the same BOM / whitespace / fence / preamble handling before
|
|
364
|
+
* scanning, and reports `offset` against that original text.
|
|
365
|
+
*
|
|
366
|
+
* Classification is **structural and deliberately conservative**. The scan
|
|
367
|
+
* walks the JSON grammar itself rather than reading the engine's error string,
|
|
368
|
+
* so its verdicts are stable across Node versions — and any fault it cannot
|
|
369
|
+
* name with confidence comes back as `'unknown'` rather than a guess. In
|
|
370
|
+
* particular an input that opened a structure and never closed it (the
|
|
371
|
+
* truncated-response shape {@link AiAssist.extractJsonText} already diagnoses)
|
|
372
|
+
* classifies as `'unknown'` here; the two diagnostics are complementary, not
|
|
373
|
+
* competing.
|
|
374
|
+
*
|
|
375
|
+
* This never fails and never repairs — it only names the fault. It is a
|
|
376
|
+
* diagnostic on the failure path, so calling it on text that parses fine is
|
|
377
|
+
* harmless but pointless: it returns `'unknown'`.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```ts
|
|
381
|
+
* const parsed = fencedStringifiedJson({ inner }).convert(raw);
|
|
382
|
+
* if (parsed.isFailure()) {
|
|
383
|
+
* const reason = classifyJsonParseFailure(raw);
|
|
384
|
+
* switch (reason.kind) {
|
|
385
|
+
* case 'unquoted-property-name': // cheap to repair
|
|
386
|
+
* case 'single-quoted-property-name':
|
|
387
|
+
* break;
|
|
388
|
+
* case 'elided-member':
|
|
389
|
+
* case 'unterminated-property-name': // worth a re-prompt
|
|
390
|
+
* break;
|
|
391
|
+
* default: // 'unknown' — fail outright
|
|
392
|
+
* }
|
|
393
|
+
* }
|
|
394
|
+
* ```
|
|
395
|
+
*
|
|
396
|
+
* @param text - Raw model output (the same string handed to the extractor).
|
|
397
|
+
* @returns A {@link AiAssist.JsonParseFailureReason}.
|
|
398
|
+
* @public
|
|
399
|
+
*/
|
|
400
|
+
function classifyJsonParseFailure(text) {
|
|
401
|
+
// Defensive, and load-bearing for the documented totality: the signature says
|
|
402
|
+
// `string`, but a JS consumer — or a TS caller coming through an `unknown` /
|
|
403
|
+
// `any` escape hatch — can still hand us a non-string, and `locateJsonCandidate`
|
|
404
|
+
// would throw on it. `extractJsonText` already guards the same way; this keeps
|
|
405
|
+
// the pair consistent and keeps "never fails" true in practice rather than only
|
|
406
|
+
// under a well-typed caller.
|
|
407
|
+
if (typeof text !== 'string') {
|
|
408
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
409
|
+
}
|
|
410
|
+
const candidate = locateJsonCandidate(text);
|
|
411
|
+
const scan = findBalancedJsonSubstring(candidate.text);
|
|
412
|
+
if (scan.kind === 'none') {
|
|
413
|
+
return UNKNOWN_PARSE_FAILURE;
|
|
414
|
+
}
|
|
415
|
+
return scanForParseFailure(candidate.text, scan.start, candidate.base);
|
|
416
|
+
}
|
|
142
417
|
function fencedStringifiedJson(options) {
|
|
143
418
|
var _a;
|
|
144
419
|
const extractor = (_a = options === null || options === void 0 ? void 0 : options.extractor) !== null && _a !== void 0 ? _a : exports.extractJsonText;
|