deepccc 0.2.22 → 0.2.23
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/decision-session.d.ts +7 -0
- package/dist/decision-session.js +38 -8
- package/dist/index.d.ts +1 -1
- package/docs/decision-session.md +10 -0
- package/package.json +1 -1
|
@@ -41,6 +41,12 @@ export interface DecisionMetrics {
|
|
|
41
41
|
contextChars: number;
|
|
42
42
|
}
|
|
43
43
|
export type DecisionFailureStatus = "timed_out" | "cancelled" | "invalid_output" | "step_limit" | "tool_error" | "context_limit" | "error";
|
|
44
|
+
export interface DecisionDiagnostic {
|
|
45
|
+
/** Fixed categories only: no provider messages, input values or credentials. */
|
|
46
|
+
code: "provider_error" | "tool_input_invalid" | "unknown_tool" | "schema_validation_failed" | "protocol_error" | "output_truncated" | "incomplete_response" | "deadline_exceeded" | "cancelled" | "budget_exceeded" | "tool_execution_failed" | "internal_error";
|
|
47
|
+
stage: "provider" | "validation" | "protocol" | "runtime" | "tool";
|
|
48
|
+
httpStatus?: number;
|
|
49
|
+
}
|
|
44
50
|
export type DecisionResult<T> = {
|
|
45
51
|
requestId: string;
|
|
46
52
|
stateVersion: string | number;
|
|
@@ -51,6 +57,7 @@ export type DecisionResult<T> = {
|
|
|
51
57
|
} | {
|
|
52
58
|
status: DecisionFailureStatus;
|
|
53
59
|
message: string;
|
|
60
|
+
diagnostic: DecisionDiagnostic;
|
|
54
61
|
});
|
|
55
62
|
/** Reusable model client; decisions do not share mutable history or invoke context compaction. */
|
|
56
63
|
export declare class DecisionSession<T> {
|
package/dist/decision-session.js
CHANGED
|
@@ -6,11 +6,30 @@ import { performance } from "node:perf_hooks";
|
|
|
6
6
|
import { config, normalizeDeepCccProvider } from "./config.js";
|
|
7
7
|
class DecisionFailure extends Error {
|
|
8
8
|
status;
|
|
9
|
-
|
|
9
|
+
diagnostic;
|
|
10
|
+
constructor(status, message, diagnostic) {
|
|
10
11
|
super(message);
|
|
11
12
|
this.status = status;
|
|
13
|
+
this.diagnostic = diagnostic;
|
|
12
14
|
}
|
|
13
15
|
}
|
|
16
|
+
function failureDiagnostic(status, error) {
|
|
17
|
+
if (status === "timed_out")
|
|
18
|
+
return { code: "deadline_exceeded", stage: "runtime" };
|
|
19
|
+
if (status === "cancelled")
|
|
20
|
+
return { code: "cancelled", stage: "runtime" };
|
|
21
|
+
if (error instanceof DecisionFailure && error.diagnostic)
|
|
22
|
+
return error.diagnostic;
|
|
23
|
+
if (status === "context_limit" || status === "step_limit")
|
|
24
|
+
return { code: "budget_exceeded", stage: "runtime" };
|
|
25
|
+
if (status === "tool_error")
|
|
26
|
+
return { code: "tool_execution_failed", stage: "tool" };
|
|
27
|
+
return { code: status === "invalid_output" ? "protocol_error" : "internal_error", stage: "runtime" };
|
|
28
|
+
}
|
|
29
|
+
function providerDiagnostic(error) {
|
|
30
|
+
const status = error && typeof error === "object" && "statusCode" in error ? error.statusCode : undefined;
|
|
31
|
+
return { code: "provider_error", stage: "provider", ...(typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599 ? { httpStatus: status } : {}) };
|
|
32
|
+
}
|
|
14
33
|
const SUBMIT = "submit_result";
|
|
15
34
|
const DEADLINE = Symbol("decision deadline");
|
|
16
35
|
function positive(value, fallback, name) {
|
|
@@ -133,7 +152,7 @@ export class DecisionSession {
|
|
|
133
152
|
const status = signal.aborted ? signal.reason === DEADLINE ? "timed_out" : "cancelled"
|
|
134
153
|
: performance.now() >= deadline ? "timed_out" : error instanceof DecisionFailure ? error.status : "error";
|
|
135
154
|
// Never echo provider errors, credentials, tool payloads or partially generated output.
|
|
136
|
-
outcome = { status, message: error instanceof DecisionFailure ? error.message : "Decision did not complete successfully" };
|
|
155
|
+
outcome = { status, message: error instanceof DecisionFailure ? error.message : "Decision did not complete successfully", diagnostic: failureDiagnostic(status, error) };
|
|
137
156
|
}
|
|
138
157
|
finally {
|
|
139
158
|
clearTimeout(timer);
|
|
@@ -155,7 +174,7 @@ export class DecisionSession {
|
|
|
155
174
|
if (!calls.length || ids.size !== calls.length)
|
|
156
175
|
throw new DecisionFailure("invalid_output", "Expected unique structured tool calls");
|
|
157
176
|
if (calls.some(c => c.toolName !== SUBMIT && !Object.hasOwn(this.tools, c.toolName))) {
|
|
158
|
-
throw new DecisionFailure("invalid_output", "Tool is not allowed");
|
|
177
|
+
throw new DecisionFailure("invalid_output", "Tool is not allowed", { code: "unknown_tool", stage: "protocol" });
|
|
159
178
|
}
|
|
160
179
|
if (calls.some(c => c.toolName === SUBMIT)) {
|
|
161
180
|
if (calls.length !== 1)
|
|
@@ -163,7 +182,7 @@ export class DecisionSession {
|
|
|
163
182
|
const validated = await abortable(Promise.resolve().then(() => this.output.validate(calls[0].input)), signal);
|
|
164
183
|
check();
|
|
165
184
|
if (!validated.success)
|
|
166
|
-
throw new DecisionFailure("invalid_output", "Result validation failed");
|
|
185
|
+
throw new DecisionFailure("invalid_output", "Result validation failed", { code: "schema_validation_failed", stage: "validation" });
|
|
167
186
|
return validated.value;
|
|
168
187
|
}
|
|
169
188
|
if (step + 1 >= this.limits.steps)
|
|
@@ -178,7 +197,7 @@ export class DecisionSession {
|
|
|
178
197
|
const validated = await abortable(Promise.resolve().then(() => asSchema(definition.inputSchema).validate(call.input)), signal);
|
|
179
198
|
check();
|
|
180
199
|
if (!validated.success)
|
|
181
|
-
throw new DecisionFailure("invalid_output", "Tool input validation failed");
|
|
200
|
+
throw new DecisionFailure("invalid_output", "Tool input validation failed", { code: "tool_input_invalid", stage: "validation" });
|
|
182
201
|
inputs.push(validated.value);
|
|
183
202
|
}
|
|
184
203
|
messages.push({ role: "assistant", content: calls.map(c => ({ type: "tool-call", ...c })) });
|
|
@@ -211,10 +230,13 @@ export class DecisionSession {
|
|
|
211
230
|
metrics.modelCalls++;
|
|
212
231
|
const result = streamText({ model: this.model, system: this.system, messages: [...messages], tools: this.modelTools,
|
|
213
232
|
toolChoice: "required", maxRetries: 0, abortSignal: signal, maxOutputTokens: this.maxOutputTokens,
|
|
233
|
+
// The SDK default logs raw errors. Return allowlisted diagnostics instead.
|
|
234
|
+
onError: () => { },
|
|
214
235
|
...(this.providerOptions ? { providerOptions: this.providerOptions } : {}) });
|
|
215
236
|
const iterator = result.fullStream[Symbol.asyncIterator]();
|
|
216
237
|
const calls = [];
|
|
217
238
|
let finish;
|
|
239
|
+
let invalidCall;
|
|
218
240
|
let chars = 0;
|
|
219
241
|
try {
|
|
220
242
|
while (true) {
|
|
@@ -223,14 +245,20 @@ export class DecisionSession {
|
|
|
223
245
|
if (next.done)
|
|
224
246
|
break;
|
|
225
247
|
const part = next.value;
|
|
226
|
-
if (part.type === "error"
|
|
227
|
-
throw new DecisionFailure("invalid_output", "Provider
|
|
248
|
+
if (part.type === "error")
|
|
249
|
+
throw new DecisionFailure("invalid_output", "Provider request failed", providerDiagnostic(part.error));
|
|
250
|
+
if (part.type === "tool-error")
|
|
251
|
+
invalidCall ??= { code: "tool_input_invalid", stage: "validation" };
|
|
228
252
|
if (part.type === "finish")
|
|
229
253
|
finish = part.finishReason;
|
|
230
254
|
if (part.type === "text-delta" || part.type === "reasoning-delta" || part.type === "tool-input-delta") {
|
|
231
255
|
chars += part.type === "tool-input-delta" ? part.delta.length : part.text.length;
|
|
232
256
|
}
|
|
233
257
|
if (part.type === "tool-call") {
|
|
258
|
+
if ("invalid" in part && part.invalid) {
|
|
259
|
+
invalidCall = { code: Object.hasOwn(this.modelTools, part.toolName) ? "tool_input_invalid" : "unknown_tool", stage: "validation" };
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
234
262
|
chars += boundedJson(part.input, this.limits.response).length;
|
|
235
263
|
calls.push({ toolCallId: part.toolCallId, toolName: part.toolName, input: part.input });
|
|
236
264
|
}
|
|
@@ -238,7 +266,9 @@ export class DecisionSession {
|
|
|
238
266
|
throw new DecisionFailure("invalid_output", "Response budget exceeded");
|
|
239
267
|
}
|
|
240
268
|
if (finish !== "stop" && finish !== "tool-calls")
|
|
241
|
-
throw new DecisionFailure("invalid_output", "Provider did not finish normally");
|
|
269
|
+
throw new DecisionFailure("invalid_output", "Provider did not finish normally", { code: finish === "length" ? "output_truncated" : "incomplete_response", stage: "protocol" });
|
|
270
|
+
if (invalidCall)
|
|
271
|
+
throw new DecisionFailure("invalid_output", "Invalid structured tool call", invalidCall);
|
|
242
272
|
return calls;
|
|
243
273
|
}
|
|
244
274
|
finally {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { type DeepCccProvider } from "./config.js";
|
|
7
7
|
import { type PermissionMode, type PermissionResolver } from "./permissions.js";
|
|
8
8
|
export { DecisionSession } from "./decision-session.js";
|
|
9
|
-
export type { DecisionModelConfig, DecisionSessionOptions, DecisionRequest, DecisionResult, DecisionMetrics, DecisionFailureStatus, DecisionTool, DecisionToolContext } from "./decision-session.js";
|
|
9
|
+
export type { DecisionModelConfig, DecisionSessionOptions, DecisionRequest, DecisionResult, DecisionMetrics, DecisionFailureStatus, DecisionDiagnostic, DecisionTool, DecisionToolContext } from "./decision-session.js";
|
|
10
10
|
export declare const DEFAULT_COMPACTION_TIMEOUT_MS: number;
|
|
11
11
|
/**
|
|
12
12
|
* 各操作系统特有的命令行指引(文本资产,维护在 os-prompts/ 目录,而非硬编码):
|
package/docs/decision-session.md
CHANGED
|
@@ -150,6 +150,16 @@ and tool call counts, and the last assembled context size. Provider/tool error
|
|
|
150
150
|
payloads and partial generated content are not copied into result messages.
|
|
151
151
|
Invalid configuration/request budgets throw before contacting the provider.
|
|
152
152
|
|
|
153
|
+
Since 0.2.23, failures also include a safe `diagnostic` object with a fixed `code`
|
|
154
|
+
and `stage`. Categories distinguish provider errors, invalid tool input, result
|
|
155
|
+
schema failures, truncated output, interrupted output, deadlines and cancellation.
|
|
156
|
+
Provider HTTP status is included when available, but error messages, raw tool
|
|
157
|
+
arguments, prompts, headers and response bodies are never copied into diagnostics.
|
|
158
|
+
The SDK's default raw error logging is disabled for this API. Integrations can
|
|
159
|
+
record their own schema issue paths inside their validators; keep values and raw
|
|
160
|
+
payloads out of those records. The original `status` remains the control-flow
|
|
161
|
+
contract. Diagnostics do not relax validation or trigger automatic retries.
|
|
162
|
+
|
|
153
163
|
Pass an optional `AbortSignal` as the second argument to `decide()`. Provider SDK
|
|
154
164
|
automatic retries are disabled; any future application retry needs a fresh,
|
|
155
165
|
explicit budget. Non-cooperative asynchronous tools/streams are raced against
|