@ycodium-ai/agent-claude 0.2.3024 → 0.2.3028

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.
Files changed (2) hide show
  1. package/dist/index.js +130 -37
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -19840,15 +19840,21 @@ function claudeSignedOutMessage(input) {
19840
19840
  }
19841
19841
  function claudeFailureHint(input) {
19842
19842
  if (input.authenticationFailed) {
19843
- return claudeSignedOutMessage({
19844
- configDir: input.environment.CLAUDE_CONFIG_DIR,
19845
- credentialsDir: input.environment[CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE],
19846
- cwd: input.cwd
19847
- });
19843
+ return {
19844
+ category: "auth",
19845
+ text: claudeSignedOutMessage({
19846
+ configDir: input.environment.CLAUDE_CONFIG_DIR,
19847
+ credentialsDir: input.environment[CLAUDE_CREDENTIALS_DIR_ENVIRONMENT_VARIABLE],
19848
+ cwd: input.cwd
19849
+ })
19850
+ };
19848
19851
  }
19849
19852
  const limit = input.usageLimit;
19850
19853
  if (limit !== void 0 && (limit.rejected.size > 0 || limit.latestAssistantRateLimited)) {
19851
- return describeUsageLimitFailure(limit.rejected, limit.nowMs);
19854
+ return {
19855
+ category: limit.rejected.size > 0 ? "quota" : "rate-limit",
19856
+ text: describeUsageLimitFailure(limit.rejected, limit.nowMs)
19857
+ };
19852
19858
  }
19853
19859
  return void 0;
19854
19860
  }
@@ -21022,10 +21028,10 @@ function resultListedError(result) {
21022
21028
  }
21023
21029
  return result.errors.find((error) => !error.startsWith("[ede_diagnostic]"));
21024
21030
  }
21025
- function terminalResultError(reason, failureHint) {
21031
+ function terminalResultError(reason) {
21026
21032
  switch (reason) {
21027
21033
  case "api_error":
21028
- return failureHint ?? "Claude gave up after repeated API errors.";
21034
+ return "Claude gave up after repeated API errors.";
21029
21035
  case "malformed_tool_use_exhausted":
21030
21036
  return "Claude gave up after repeated malformed tool calls.";
21031
21037
  case "budget_exhausted":
@@ -21037,7 +21043,7 @@ function terminalResultError(reason, failureHint) {
21037
21043
  case "turn_setup_failed":
21038
21044
  return "Claude could not start the turn.";
21039
21045
  case "blocking_limit":
21040
- return failureHint ?? "Claude stopped: a usage limit blocked the request.";
21046
+ return "Claude stopped: a usage limit blocked the request.";
21041
21047
  case "rapid_refill_breaker":
21042
21048
  return "Claude stopped: the context refilled too quickly after compaction.";
21043
21049
  case "prompt_too_long":
@@ -21063,17 +21069,30 @@ function isInterruptedResult(result) {
21063
21069
  }
21064
21070
  return result.subtype === "error_during_execution" && result.is_error === false && (errors.includes("request was aborted") || errors.includes("interrupted by user") || errors.includes("aborted"));
21065
21071
  }
21066
- function resultOutcome(result, failureHint) {
21067
- const structuredError = isOverloadedResult(result) ? "Claude API is overloaded (529). Try again shortly." : terminalResultError(result.terminal_reason, failureHint);
21068
- const successTaggedFailure = result.subtype === "success" && result.is_error;
21069
- const errorMessage = (successTaggedFailure ? failureHint : void 0) ?? resultListedError(result) ?? structuredError;
21070
- if (structuredError !== void 0) return { status: "failed", errorMessage };
21072
+ function resultOutcome(result, hint) {
21073
+ const overloaded = isOverloadedResult(result);
21074
+ const terminalText = overloaded ? void 0 : terminalResultError(result.terminal_reason);
21075
+ const fromResult = {
21076
+ from: "result",
21077
+ reason: overloaded ? "overloaded" : terminalText === void 0 ? void 0 : result.terminal_reason
21078
+ };
21079
+ const hinted = hint === void 0 ? void 0 : { text: hint.text, cause: { from: "hint", category: hint.category } };
21080
+ const listed = resultListedError(result);
21081
+ const terminalReason = result.terminal_reason;
21082
+ const blanketTerminal = terminalReason === "api_error" || terminalReason === "blocking_limit";
21083
+ const chosen = result.subtype === "success" && result.is_error && hinted !== void 0 ? hinted : listed !== void 0 ? { text: listed, cause: fromResult } : overloaded ? { text: "Claude API is overloaded (529). Try again shortly.", cause: fromResult } : terminalText !== void 0 && blanketTerminal && hinted !== void 0 ? hinted : { text: terminalText, cause: fromResult };
21084
+ const errorMessage = chosen.text;
21085
+ if (overloaded || terminalText !== void 0) {
21086
+ return { status: "failed", errorMessage, cause: chosen.cause };
21087
+ }
21071
21088
  if (result.subtype === "success" && !result.is_error) {
21072
- return { status: "completed", errorMessage };
21089
+ return { status: "completed", errorMessage, cause: void 0 };
21073
21090
  }
21074
- if (isInterruptedResult(result)) return { status: "interrupted", errorMessage };
21075
- const cancelled = resultErrorsText(result).includes("cancel");
21076
- return cancelled ? { status: "cancelled", errorMessage } : { status: "failed", errorMessage: errorMessage ?? failureHint };
21091
+ if (isInterruptedResult(result)) return { status: "interrupted", errorMessage, cause: void 0 };
21092
+ if (resultErrorsText(result).includes("cancel")) {
21093
+ return { status: "cancelled", errorMessage, cause: void 0 };
21094
+ }
21095
+ return errorMessage === void 0 && hinted !== void 0 ? { status: "failed", errorMessage: hinted.text, cause: hinted.cause } : { status: "failed", errorMessage, cause: chosen.cause };
21077
21096
  }
21078
21097
  function streamKindFromDeltaType(deltaType) {
21079
21098
  return deltaType.includes("thinking") ? "reasoning_text" : "assistant_text";
@@ -21520,6 +21539,48 @@ var makeAssistantText = (emitter) => {
21520
21539
  };
21521
21540
  };
21522
21541
 
21542
+ // src/failureCategory.ts
21543
+ var namesNoReason = (signals) => {
21544
+ const reason = signals.cause?.from === "result" ? signals.cause.reason : void 0;
21545
+ return (reason === void 0 || reason === "api_error") && (signals.resultSubtype == null || signals.resultSubtype === "success" || signals.resultSubtype === "error_during_execution");
21546
+ };
21547
+ var claudeFailureCategory = (signals) => {
21548
+ const cause = signals.cause;
21549
+ if (cause?.from === "hint") return cause.category;
21550
+ switch (cause?.reason) {
21551
+ case "overloaded":
21552
+ return "model-unavailable";
21553
+ case "prompt_too_long":
21554
+ return "context-limit";
21555
+ case "blocking_limit":
21556
+ return "quota";
21557
+ default:
21558
+ break;
21559
+ }
21560
+ if (!namesNoReason(signals)) return void 0;
21561
+ const status = signals.apiErrorStatus ?? signals.retryErrorStatus;
21562
+ if (signals.assistantError === "authentication_failed" || signals.assistantError === "oauth_org_not_allowed" || status === 401 || status === 403) {
21563
+ return "auth";
21564
+ }
21565
+ if (status === 529 || signals.structuredErrorType === "overloaded_error" || signals.assistantError === "overloaded" || signals.assistantError === "model_not_found") {
21566
+ return "model-unavailable";
21567
+ }
21568
+ if (signals.assistantError === "billing_error") return "quota";
21569
+ if (signals.assistantError === "rate_limit" || status === 429) {
21570
+ return signals.quotaWindowRejected === true ? "quota" : "rate-limit";
21571
+ }
21572
+ if (signals.establishedStreamExit === true) return "transport";
21573
+ return void 0;
21574
+ };
21575
+ var failureCategoryField = (category) => category === void 0 ? {} : { failureCategory: category };
21576
+ var claudeStructuredErrorType = (value) => {
21577
+ if (typeof value !== "object" || value === null) return void 0;
21578
+ const error = value.error;
21579
+ if (typeof error !== "object" || error === null) return void 0;
21580
+ const type4 = error.type;
21581
+ return typeof type4 === "string" ? type4 : void 0;
21582
+ };
21583
+
21523
21584
  // src/usage.ts
21524
21585
  function maxClaudeContextWindowFromModelUsage(modelUsage) {
21525
21586
  if (!modelUsage) return void 0;
@@ -21964,7 +22025,7 @@ var makeEmitters = (emitter) => {
21964
22025
  });
21965
22026
  }
21966
22027
  };
21967
- const emitRuntimeError = async (context, message, cause) => {
22028
+ const emitRuntimeError = async (context, message, cause, failureCategory) => {
21968
22029
  const turnState = context.turnState;
21969
22030
  const stamp = await makeEventStamp();
21970
22031
  offerRuntimeEvent(context, {
@@ -21974,7 +22035,8 @@ var makeEmitters = (emitter) => {
21974
22035
  payload: {
21975
22036
  message,
21976
22037
  class: "provider_error",
21977
- ...cause !== void 0 ? { detail: cause } : {}
22038
+ ...cause !== void 0 ? { detail: cause } : {},
22039
+ ...failureCategoryField(failureCategory)
21978
22040
  },
21979
22041
  providerRefs: nativeProviderRefs()
21980
22042
  });
@@ -22504,17 +22566,23 @@ var makeSdkStream = (deps) => {
22504
22566
  }
22505
22567
  };
22506
22568
  const runSdkStream = async (context) => {
22569
+ let handlerThrew = false;
22507
22570
  try {
22508
22571
  for await (const message of context.query) {
22509
22572
  if (context.stopped) break;
22510
- await handleSdkMessage(context, message);
22573
+ try {
22574
+ await handleSdkMessage(context, message);
22575
+ } catch (cause) {
22576
+ handlerThrew = true;
22577
+ throw cause;
22578
+ }
22511
22579
  }
22512
- await handleStreamExit(context, null);
22580
+ await handleStreamExit(context, null, false);
22513
22581
  } catch (cause) {
22514
- await handleStreamExit(context, cause);
22582
+ await handleStreamExit(context, cause, !handlerThrew);
22515
22583
  }
22516
22584
  };
22517
- const handleStreamExit = async (context, cause) => {
22585
+ const handleStreamExit = async (context, cause, streamBroke) => {
22518
22586
  if (context.stopped) {
22519
22587
  return;
22520
22588
  }
@@ -22527,8 +22595,11 @@ var makeSdkStream = (deps) => {
22527
22595
  const cliSaid = context.stderrTail.read();
22528
22596
  const reason = cause instanceof Error ? cause.message : "Claude runtime stream failed.";
22529
22597
  const message = cliSaid.length > 0 ? `${reason}: ${cliSaid}` : reason;
22530
- await emitRuntimeError(context, message, { cause: String(cause) });
22531
- await completeTurn(context, "failed", message);
22598
+ const category = claudeFailureCategory({
22599
+ establishedStreamExit: streamBroke && context.sessionEstablished
22600
+ });
22601
+ await emitRuntimeError(context, message, { cause: String(cause) }, category);
22602
+ await completeTurn(context, "failed", message, void 0, category);
22532
22603
  }
22533
22604
  } else if (context.turnState) {
22534
22605
  await completeTurn(context, "interrupted", "Claude runtime stream ended.");
@@ -22935,7 +23006,8 @@ var makeSendTurn = (deps) => {
22935
23006
  nextSyntheticAssistantBlockIndex: -1,
22936
23007
  rejectedRateLimits: /* @__PURE__ */ new Map(),
22937
23008
  announcedUsageLimits: /* @__PURE__ */ new Set(),
22938
- latestAssistantRateLimited: false
23009
+ latestAssistantError: void 0,
23010
+ lastRetryErrorStatus: void 0
22939
23011
  };
22940
23012
  const updatedAt = nowIso();
22941
23013
  context.turnState = turnState;
@@ -23869,6 +23941,7 @@ var makeStartSession = (deps) => {
23869
23941
  lastThreadStartedId: void 0,
23870
23942
  stopping: false,
23871
23943
  stopped: false,
23944
+ sessionEstablished: false,
23872
23945
  stopWork: void 0
23873
23946
  };
23874
23947
  contextDeferred.resolve(context);
@@ -23943,6 +24016,7 @@ var makeStreamEventHandler = (deps) => {
23943
24016
  const turnState = context.turnState;
23944
24017
  if (!turnState?.retrying) return;
23945
24018
  turnState.retrying = false;
24019
+ turnState.lastRetryErrorStatus = void 0;
23946
24020
  const stamp = await makeEventStamp();
23947
24021
  offerRuntimeEvent(context, {
23948
24022
  type: "session.state.changed",
@@ -24361,6 +24435,7 @@ var makeSystemMessageHandler = (deps) => {
24361
24435
  if (message.type !== "system") {
24362
24436
  return;
24363
24437
  }
24438
+ context.sessionEstablished = true;
24364
24439
  const stamp = await makeEventStamp();
24365
24440
  const base = {
24366
24441
  ...eventHeader(context, stamp),
@@ -24698,7 +24773,10 @@ var makeSystemMessageHandler = (deps) => {
24698
24773
  return;
24699
24774
  case "api_retry":
24700
24775
  if (message.parent_tool_use_id != null) return;
24701
- if (context.turnState) context.turnState.retrying = true;
24776
+ if (context.turnState) {
24777
+ context.turnState.retrying = true;
24778
+ context.turnState.lastRetryErrorStatus = message.error_status;
24779
+ }
24702
24780
  offerRuntimeEvent(context, {
24703
24781
  ...base,
24704
24782
  type: "session.state.changed",
@@ -24715,7 +24793,10 @@ var makeSystemMessageHandler = (deps) => {
24715
24793
  });
24716
24794
  return;
24717
24795
  case "session_state_changed":
24718
- if (message.state === "idle" && context.turnState) context.turnState.retrying = false;
24796
+ if (message.state === "idle" && context.turnState) {
24797
+ context.turnState.retrying = false;
24798
+ context.turnState.lastRetryErrorStatus = void 0;
24799
+ }
24719
24800
  offerRuntimeEvent(context, {
24720
24801
  ...base,
24721
24802
  type: "session.state.changed",
@@ -24886,7 +24967,8 @@ var makeTurnLifecycle = (deps) => {
24886
24967
  nextSyntheticAssistantBlockIndex: -1,
24887
24968
  rejectedRateLimits: /* @__PURE__ */ new Map(),
24888
24969
  announcedUsageLimits: /* @__PURE__ */ new Set(),
24889
- latestAssistantRateLimited: false
24970
+ latestAssistantError: void 0,
24971
+ lastRetryErrorStatus: void 0
24890
24972
  };
24891
24973
  context.session = {
24892
24974
  ...context.session,
@@ -24911,7 +24993,7 @@ var makeTurnLifecycle = (deps) => {
24911
24993
  }
24912
24994
  });
24913
24995
  };
24914
- const completeTurn = async (context, status, errorMessage, result) => {
24996
+ const completeTurn = async (context, status, errorMessage, result, failureCategory) => {
24915
24997
  const resultContextWindow = maxClaudeContextWindowFromModelUsage(result?.modelUsage);
24916
24998
  if (resultContextWindow !== void 0) {
24917
24999
  context.lastKnownContextWindow = resultContextWindow;
@@ -25020,7 +25102,8 @@ var makeTurnLifecycle = (deps) => {
25020
25102
  ...result?.usage ? { usage: result.usage } : {},
25021
25103
  ...result?.modelUsage ? { modelUsage: result.modelUsage } : {},
25022
25104
  ...typeof result?.total_cost_usd === "number" ? { totalCostUsd: result.total_cost_usd } : {},
25023
- ...errorMessage ? { errorMessage } : {}
25105
+ ...errorMessage ? { errorMessage } : {},
25106
+ ...status === "failed" ? failureCategoryField(failureCategory) : {}
25024
25107
  },
25025
25108
  providerRefs: nativeProviderRefs()
25026
25109
  });
@@ -25223,7 +25306,7 @@ var makeTurnMessageHandlers = (deps) => {
25223
25306
  }
25224
25307
  const rateLimitParent = message.parent_tool_use_id;
25225
25308
  if (context.turnState && (rateLimitParent === null || rateLimitParent === void 0)) {
25226
- context.turnState.latestAssistantRateLimited = message.error === "rate_limit";
25309
+ context.turnState.latestAssistantError = typeof message.error === "string" ? message.error : void 0;
25227
25310
  }
25228
25311
  if (isClaudeSyntheticApiErrorMessage(message)) {
25229
25312
  if (context.turnState && message.error === "authentication_failed") {
@@ -25305,17 +25388,27 @@ var makeTurnMessageHandlers = (deps) => {
25305
25388
  ...context.turnState === void 0 ? {} : {
25306
25389
  usageLimit: {
25307
25390
  rejected: context.turnState.rejectedRateLimits,
25308
- latestAssistantRateLimited: context.turnState.latestAssistantRateLimited,
25391
+ latestAssistantRateLimited: context.turnState.latestAssistantError === "rate_limit",
25309
25392
  nowMs: now()
25310
25393
  }
25311
25394
  }
25312
25395
  })
25313
25396
  );
25314
- const { status, errorMessage } = outcome;
25397
+ const { status, errorMessage, cause } = outcome;
25398
+ const turn = context.turnState;
25399
+ const category = status === "failed" ? claudeFailureCategory({
25400
+ cause,
25401
+ resultSubtype: message.subtype,
25402
+ apiErrorStatus: "api_error_status" in message ? message.api_error_status : void 0,
25403
+ retryErrorStatus: turn?.lastRetryErrorStatus,
25404
+ assistantError: turn?.latestAssistantError,
25405
+ quotaWindowRejected: (turn?.rejectedRateLimits.size ?? 0) > 0,
25406
+ structuredErrorType: claudeStructuredErrorType(message)
25407
+ }) : void 0;
25315
25408
  if (status === "failed") {
25316
- await emitRuntimeError(context, errorMessage ?? "Claude turn failed.");
25409
+ await emitRuntimeError(context, errorMessage ?? "Claude turn failed.", void 0, category);
25317
25410
  }
25318
- await completeTurn(context, status, errorMessage, message);
25411
+ await completeTurn(context, status, errorMessage, message, category);
25319
25412
  };
25320
25413
  return { handleUserMessage, handleAssistantMessage, handleResultMessage };
25321
25414
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-claude",
3
- "version": "0.2.3024",
3
+ "version": "0.2.3028",
4
4
  "description": "Claude executor: Claude Code CLI via @anthropic-ai/claude-agent-sdk.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -24,10 +24,10 @@
24
24
  "@types/node": "24.12.4",
25
25
  "esbuild": "0.28.1",
26
26
  "vite-plus": "0.2.2",
27
- "@ycodium-ai/plugin-api": "0.2.3024",
28
- "ycodium-composer-tokens": "0.0.0",
27
+ "@ycodium-ai/plugin-api": "0.2.3028",
29
28
  "ycodium-jsonl-stream": "0.0.0",
30
- "ycodium-executor-testing": "0.0.0"
29
+ "ycodium-executor-testing": "0.0.0",
30
+ "ycodium-composer-tokens": "0.0.0"
31
31
  },
32
32
  "ycodium": {
33
33
  "plugin": "./dist/index.js",