@jaypie/llm 1.3.12 → 1.3.13
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/cjs/index.cjs +79 -3
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/operate/adapters/FireworksAdapter.d.ts +1 -0
- package/dist/cjs/operate/adapters/ProviderAdapter.interface.d.ts +13 -0
- package/dist/cjs/operate/types.d.ts +9 -0
- package/dist/esm/index.js +79 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operate/adapters/FireworksAdapter.d.ts +1 -0
- package/dist/esm/operate/adapters/ProviderAdapter.interface.d.ts +13 -0
- package/dist/esm/operate/types.d.ts +9 -0
- package/package.json +1 -1
|
@@ -106,6 +106,7 @@ type FireworksContentPart = {
|
|
|
106
106
|
export declare class FireworksAdapter extends BaseProviderAdapter {
|
|
107
107
|
readonly name: "fireworks";
|
|
108
108
|
readonly defaultModel: string;
|
|
109
|
+
readonly supportsStructuredOutputRetry = true;
|
|
109
110
|
private runtimeNoStructuredOutputModels;
|
|
110
111
|
rememberModelRejectsStructuredOutput(model: string): void;
|
|
111
112
|
clearRuntimeNoStructuredOutputModels(): void;
|
|
@@ -20,6 +20,12 @@ export interface ProviderAdapter {
|
|
|
20
20
|
* Default model for this provider
|
|
21
21
|
*/
|
|
22
22
|
readonly defaultModel: string;
|
|
23
|
+
/**
|
|
24
|
+
* Whether OperateLoop may take a corrective turn when a `format` request
|
|
25
|
+
* completes with prose instead of structured output (tool-emulation
|
|
26
|
+
* providers opt in).
|
|
27
|
+
*/
|
|
28
|
+
readonly supportsStructuredOutputRetry?: boolean;
|
|
23
29
|
/**
|
|
24
30
|
* Build a provider-specific request from the standardized format
|
|
25
31
|
*
|
|
@@ -169,6 +175,13 @@ export declare abstract class BaseProviderAdapter implements ProviderAdapter {
|
|
|
169
175
|
abstract responseToHistoryItems(response: unknown): LlmHistory;
|
|
170
176
|
abstract classifyError(error: unknown): ClassifiedError;
|
|
171
177
|
abstract isComplete(response: unknown): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Whether OperateLoop may take a corrective turn when a `format` request
|
|
180
|
+
* completes with prose instead of structured output. Providers whose
|
|
181
|
+
* structured output rides a tool emulation (where compliance is a model
|
|
182
|
+
* decision) opt in; native grammar-constrained providers do not need it.
|
|
183
|
+
*/
|
|
184
|
+
readonly supportsStructuredOutputRetry: boolean;
|
|
172
185
|
/**
|
|
173
186
|
* Default implementation checks if error is retryable via classifyError
|
|
174
187
|
*/
|
|
@@ -77,6 +77,13 @@ export interface OperateRequest {
|
|
|
77
77
|
stream?: boolean;
|
|
78
78
|
/** Sampling temperature (0-2 for most providers) */
|
|
79
79
|
temperature?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Set by OperateLoop on a corrective turn after a format request came back
|
|
82
|
+
* as prose. Adapters that support the retry (see
|
|
83
|
+
* `ProviderAdapter.supportsStructuredOutputRetry`) should offer only the
|
|
84
|
+
* structured-output mechanism on this turn.
|
|
85
|
+
*/
|
|
86
|
+
structuredOutputRetry?: boolean;
|
|
80
87
|
/** User identifier for tracking */
|
|
81
88
|
user?: string;
|
|
82
89
|
}
|
|
@@ -135,6 +142,8 @@ import type { ResponseBuilder } from "./response/ResponseBuilder.js";
|
|
|
135
142
|
export interface OperateLoopState {
|
|
136
143
|
/** Count of consecutive tool errors (resets on success) */
|
|
137
144
|
consecutiveToolErrors: number;
|
|
145
|
+
/** Set when the loop has taken a corrective structured-output turn */
|
|
146
|
+
structuredOutputRetry?: boolean;
|
|
138
147
|
/** Current conversation input/messages */
|
|
139
148
|
currentInput: LlmHistory;
|
|
140
149
|
/** Current turn number (0-indexed, incremented at start of each turn) */
|
package/dist/esm/index.js
CHANGED
|
@@ -482,6 +482,15 @@ function resolveModelChain(model) {
|
|
|
482
482
|
* Providers can extend this class to reduce boilerplate.
|
|
483
483
|
*/
|
|
484
484
|
class BaseProviderAdapter {
|
|
485
|
+
constructor() {
|
|
486
|
+
/**
|
|
487
|
+
* Whether OperateLoop may take a corrective turn when a `format` request
|
|
488
|
+
* completes with prose instead of structured output. Providers whose
|
|
489
|
+
* structured output rides a tool emulation (where compliance is a model
|
|
490
|
+
* decision) opt in; native grammar-constrained providers do not need it.
|
|
491
|
+
*/
|
|
492
|
+
this.supportsStructuredOutputRetry = false;
|
|
493
|
+
}
|
|
485
494
|
/**
|
|
486
495
|
* Default implementation checks if error is retryable via classifyError
|
|
487
496
|
*/
|
|
@@ -3409,6 +3418,10 @@ class FireworksAdapter extends BaseProviderAdapter {
|
|
|
3409
3418
|
super(...arguments);
|
|
3410
3419
|
this.name = PROVIDER.FIREWORKS.NAME;
|
|
3411
3420
|
this.defaultModel = PROVIDER.FIREWORKS.DEFAULT;
|
|
3421
|
+
// Structured output with tools rides the structured_output tool emulation
|
|
3422
|
+
// (Fireworks rejects response_format + tools), and emulation compliance is
|
|
3423
|
+
// a model decision — opt in to OperateLoop's corrective retry turn.
|
|
3424
|
+
this.supportsStructuredOutputRetry = true;
|
|
3412
3425
|
// Session-level cache of models observed to reject native
|
|
3413
3426
|
// `response_format: json_schema`. When a model is in this set, buildRequest
|
|
3414
3427
|
// engages the legacy fake-tool path instead of native structured output.
|
|
@@ -3463,9 +3476,10 @@ class FireworksAdapter extends BaseProviderAdapter {
|
|
|
3463
3476
|
const useFallbackStructuredOutput = Boolean(request.format) &&
|
|
3464
3477
|
(hasCallerTools ||
|
|
3465
3478
|
!this.supportsStructuredOutput(fireworksRequest.model));
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3479
|
+
// On a corrective retry turn (the model answered a format request with
|
|
3480
|
+
// prose), offer only the structured_output tool so the demanded call is
|
|
3481
|
+
// the sole option.
|
|
3482
|
+
const allTools = request.tools && !request.structuredOutputRetry ? [...request.tools] : [];
|
|
3469
3483
|
if (useFallbackStructuredOutput && request.format) {
|
|
3470
3484
|
log$2.warn(hasCallerTools
|
|
3471
3485
|
? `[FireworksAdapter] Fireworks does not support response_format combined with tools; using structured_output tool emulation for model ${fireworksRequest.model}.`
|
|
@@ -8006,6 +8020,31 @@ function createErrorClassifier(adapter) {
|
|
|
8006
8020
|
},
|
|
8007
8021
|
};
|
|
8008
8022
|
}
|
|
8023
|
+
/**
|
|
8024
|
+
* Attempt to read a prose response as the structured payload itself: parse the
|
|
8025
|
+
* text (stripping a Markdown code fence if present) and return the object, or
|
|
8026
|
+
* undefined when the text is not a JSON object.
|
|
8027
|
+
*/
|
|
8028
|
+
function tryParseJsonObject(text) {
|
|
8029
|
+
let candidate = text.trim();
|
|
8030
|
+
const fence = candidate.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/);
|
|
8031
|
+
if (fence) {
|
|
8032
|
+
candidate = fence[1].trim();
|
|
8033
|
+
}
|
|
8034
|
+
if (!candidate.startsWith("{")) {
|
|
8035
|
+
return undefined;
|
|
8036
|
+
}
|
|
8037
|
+
try {
|
|
8038
|
+
const parsed = JSON.parse(candidate);
|
|
8039
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
8040
|
+
return parsed;
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
8043
|
+
catch {
|
|
8044
|
+
// Not JSON; caller falls through to the corrective-turn path.
|
|
8045
|
+
}
|
|
8046
|
+
return undefined;
|
|
8047
|
+
}
|
|
8009
8048
|
//
|
|
8010
8049
|
//
|
|
8011
8050
|
// Main
|
|
@@ -8074,6 +8113,7 @@ class OperateLoop {
|
|
|
8074
8113
|
messages: state.currentInput,
|
|
8075
8114
|
model: modelName,
|
|
8076
8115
|
providerOptions: options.providerOptions,
|
|
8116
|
+
structuredOutputRetry: state.structuredOutputRetry,
|
|
8077
8117
|
system: options.system,
|
|
8078
8118
|
temperature: options.temperature,
|
|
8079
8119
|
tools: state.formattedTools,
|
|
@@ -8477,6 +8517,42 @@ class OperateLoop {
|
|
|
8477
8517
|
return true; // Continue to next turn
|
|
8478
8518
|
}
|
|
8479
8519
|
}
|
|
8520
|
+
// Format contract enforcement: the loop is about to complete but the
|
|
8521
|
+
// model answered with prose instead of structured output.
|
|
8522
|
+
if (state.formattedFormat && typeof parsed.content === "string") {
|
|
8523
|
+
// First salvage attempt: the text may be the JSON itself (with or
|
|
8524
|
+
// without a code fence).
|
|
8525
|
+
const salvaged = tryParseJsonObject(parsed.content);
|
|
8526
|
+
if (salvaged) {
|
|
8527
|
+
state.responseBuilder.setContent(this.applyFormatArrayDefaults(salvaged, options));
|
|
8528
|
+
state.responseBuilder.complete();
|
|
8529
|
+
for (const item of this.adapter.responseToHistoryItems(parsed.raw)) {
|
|
8530
|
+
state.responseBuilder.appendToHistory(item);
|
|
8531
|
+
}
|
|
8532
|
+
return false; // Stop loop
|
|
8533
|
+
}
|
|
8534
|
+
// Corrective turn: for adapters whose structured output rides a tool
|
|
8535
|
+
// emulation, take another turn offering only the structured_output tool
|
|
8536
|
+
// and demand it be called. Bounded by maxTurns.
|
|
8537
|
+
if (this.adapter.supportsStructuredOutputRetry &&
|
|
8538
|
+
state.currentTurn < state.maxTurns) {
|
|
8539
|
+
log.warn(`[operate] Model returned text despite format on turn ${state.currentTurn}; retrying with structured_output tool only`);
|
|
8540
|
+
for (const item of this.adapter.responseToHistoryItems(parsed.raw)) {
|
|
8541
|
+
state.currentInput.push(item);
|
|
8542
|
+
state.responseBuilder.appendToHistory(item);
|
|
8543
|
+
}
|
|
8544
|
+
const corrective = {
|
|
8545
|
+
content: "You must provide your final answer by calling the structured_output tool " +
|
|
8546
|
+
"with arguments matching the required schema. Do not respond with text.",
|
|
8547
|
+
role: LlmMessageRole.User,
|
|
8548
|
+
type: LlmMessageType.Message,
|
|
8549
|
+
};
|
|
8550
|
+
state.currentInput.push(corrective);
|
|
8551
|
+
state.responseBuilder.appendToHistory(corrective);
|
|
8552
|
+
state.structuredOutputRetry = true;
|
|
8553
|
+
return true; // Continue to corrective turn
|
|
8554
|
+
}
|
|
8555
|
+
}
|
|
8480
8556
|
// No tool calls or no toolkit - we're done
|
|
8481
8557
|
state.responseBuilder.setContent(this.applyFormatArrayDefaults(parsed.content, options));
|
|
8482
8558
|
state.responseBuilder.complete();
|