@witqq/agent-sdk 0.6.1 → 0.8.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.
Files changed (145) hide show
  1. package/README.md +539 -6
  2. package/dist/{types-BvwNzZCj.d.cts → agent-CW9XbmG_.d.ts} +148 -95
  3. package/dist/{types-BvwNzZCj.d.ts → agent-DxY68NZL.d.cts} +148 -95
  4. package/dist/auth/index.cjs +260 -2
  5. package/dist/auth/index.cjs.map +1 -1
  6. package/dist/auth/index.d.cts +21 -138
  7. package/dist/auth/index.d.ts +21 -138
  8. package/dist/auth/index.js +260 -3
  9. package/dist/auth/index.js.map +1 -1
  10. package/dist/backends/claude.cjs +653 -140
  11. package/dist/backends/claude.cjs.map +1 -1
  12. package/dist/backends/claude.d.cts +4 -1
  13. package/dist/backends/claude.d.ts +4 -1
  14. package/dist/backends/claude.js +653 -140
  15. package/dist/backends/claude.js.map +1 -1
  16. package/dist/backends/copilot.cjs +428 -88
  17. package/dist/backends/copilot.cjs.map +1 -1
  18. package/dist/backends/copilot.d.cts +13 -4
  19. package/dist/backends/copilot.d.ts +13 -4
  20. package/dist/backends/copilot.js +428 -88
  21. package/dist/backends/copilot.js.map +1 -1
  22. package/dist/backends/vercel-ai.cjs +349 -77
  23. package/dist/backends/vercel-ai.cjs.map +1 -1
  24. package/dist/backends/vercel-ai.d.cts +3 -1
  25. package/dist/backends/vercel-ai.d.ts +3 -1
  26. package/dist/backends/vercel-ai.js +349 -77
  27. package/dist/backends/vercel-ai.js.map +1 -1
  28. package/dist/backends-BSrsBYFn.d.cts +39 -0
  29. package/dist/backends-BSrsBYFn.d.ts +39 -0
  30. package/dist/chat/accumulator.cjs +147 -0
  31. package/dist/chat/accumulator.cjs.map +1 -0
  32. package/dist/chat/accumulator.d.cts +64 -0
  33. package/dist/chat/accumulator.d.ts +64 -0
  34. package/dist/chat/accumulator.js +145 -0
  35. package/dist/chat/accumulator.js.map +1 -0
  36. package/dist/chat/backends.cjs +3524 -0
  37. package/dist/chat/backends.cjs.map +1 -0
  38. package/dist/chat/backends.d.cts +66 -0
  39. package/dist/chat/backends.d.ts +66 -0
  40. package/dist/chat/backends.js +3512 -0
  41. package/dist/chat/backends.js.map +1 -0
  42. package/dist/chat/context.cjs +280 -0
  43. package/dist/chat/context.cjs.map +1 -0
  44. package/dist/chat/context.d.cts +191 -0
  45. package/dist/chat/context.d.ts +191 -0
  46. package/dist/chat/context.js +277 -0
  47. package/dist/chat/context.js.map +1 -0
  48. package/dist/chat/core.cjs +305 -0
  49. package/dist/chat/core.cjs.map +1 -0
  50. package/dist/chat/core.d.cts +84 -0
  51. package/dist/chat/core.d.ts +84 -0
  52. package/dist/chat/core.js +282 -0
  53. package/dist/chat/core.js.map +1 -0
  54. package/dist/chat/errors.cjs +273 -0
  55. package/dist/chat/errors.cjs.map +1 -0
  56. package/dist/chat/errors.d.cts +97 -0
  57. package/dist/chat/errors.d.ts +97 -0
  58. package/dist/chat/errors.js +266 -0
  59. package/dist/chat/errors.js.map +1 -0
  60. package/dist/chat/events.cjs +203 -0
  61. package/dist/chat/events.cjs.map +1 -0
  62. package/dist/chat/events.d.cts +245 -0
  63. package/dist/chat/events.d.ts +245 -0
  64. package/dist/chat/events.js +196 -0
  65. package/dist/chat/events.js.map +1 -0
  66. package/dist/chat/index.cjs +5550 -0
  67. package/dist/chat/index.cjs.map +1 -0
  68. package/dist/chat/index.d.cts +77 -0
  69. package/dist/chat/index.d.ts +77 -0
  70. package/dist/chat/index.js +5505 -0
  71. package/dist/chat/index.js.map +1 -0
  72. package/dist/chat/react/theme.css +2517 -0
  73. package/dist/chat/react.cjs +3589 -0
  74. package/dist/chat/react.cjs.map +1 -0
  75. package/dist/chat/react.d.cts +1088 -0
  76. package/dist/chat/react.d.ts +1088 -0
  77. package/dist/chat/react.js +3547 -0
  78. package/dist/chat/react.js.map +1 -0
  79. package/dist/chat/runtime.cjs +1245 -0
  80. package/dist/chat/runtime.cjs.map +1 -0
  81. package/dist/chat/runtime.d.cts +182 -0
  82. package/dist/chat/runtime.d.ts +182 -0
  83. package/dist/chat/runtime.js +1243 -0
  84. package/dist/chat/runtime.js.map +1 -0
  85. package/dist/chat/server.cjs +2668 -0
  86. package/dist/chat/server.cjs.map +1 -0
  87. package/dist/chat/server.d.cts +648 -0
  88. package/dist/chat/server.d.ts +648 -0
  89. package/dist/chat/server.js +2628 -0
  90. package/dist/chat/server.js.map +1 -0
  91. package/dist/chat/sessions.cjs +380 -0
  92. package/dist/chat/sessions.cjs.map +1 -0
  93. package/dist/chat/sessions.d.cts +158 -0
  94. package/dist/chat/sessions.d.ts +158 -0
  95. package/dist/chat/sessions.js +376 -0
  96. package/dist/chat/sessions.js.map +1 -0
  97. package/dist/chat/sqlite.cjs +441 -0
  98. package/dist/chat/sqlite.cjs.map +1 -0
  99. package/dist/chat/sqlite.d.cts +128 -0
  100. package/dist/chat/sqlite.d.ts +128 -0
  101. package/dist/chat/sqlite.js +435 -0
  102. package/dist/chat/sqlite.js.map +1 -0
  103. package/dist/chat/state.cjs +190 -0
  104. package/dist/chat/state.cjs.map +1 -0
  105. package/dist/chat/state.d.cts +95 -0
  106. package/dist/chat/state.d.ts +95 -0
  107. package/dist/chat/state.js +180 -0
  108. package/dist/chat/state.js.map +1 -0
  109. package/dist/chat/storage.cjs +249 -0
  110. package/dist/chat/storage.cjs.map +1 -0
  111. package/dist/chat/storage.d.cts +197 -0
  112. package/dist/chat/storage.d.ts +197 -0
  113. package/dist/chat/storage.js +245 -0
  114. package/dist/chat/storage.js.map +1 -0
  115. package/dist/errors-C-so0M4t.d.cts +33 -0
  116. package/dist/errors-C-so0M4t.d.ts +33 -0
  117. package/dist/errors-CmVvczxZ.d.cts +28 -0
  118. package/dist/errors-CmVvczxZ.d.ts +28 -0
  119. package/dist/in-process-transport-C1JnJGVR.d.ts +228 -0
  120. package/dist/in-process-transport-C7DSqPyX.d.cts +228 -0
  121. package/dist/index.cjs +365 -59
  122. package/dist/index.cjs.map +1 -1
  123. package/dist/index.d.cts +322 -125
  124. package/dist/index.d.ts +322 -125
  125. package/dist/index.js +359 -60
  126. package/dist/index.js.map +1 -1
  127. package/dist/provider-types-PTSlRPNB.d.cts +39 -0
  128. package/dist/provider-types-PTSlRPNB.d.ts +39 -0
  129. package/dist/refresh-manager-B81PpYBr.d.cts +153 -0
  130. package/dist/refresh-manager-Dlv_iNZi.d.ts +153 -0
  131. package/dist/testing.cjs +383 -0
  132. package/dist/testing.cjs.map +1 -0
  133. package/dist/testing.d.cts +132 -0
  134. package/dist/testing.d.ts +132 -0
  135. package/dist/testing.js +377 -0
  136. package/dist/testing.js.map +1 -0
  137. package/dist/token-store-CSUBgYwn.d.ts +48 -0
  138. package/dist/token-store-CuC4hB9Z.d.cts +48 -0
  139. package/dist/transport-Cdh3M0tS.d.cts +68 -0
  140. package/dist/transport-Ciap4PWK.d.ts +68 -0
  141. package/dist/types-4vbcmPTp.d.cts +143 -0
  142. package/dist/types-BxggH0Yh.d.ts +143 -0
  143. package/dist/types-DRgd_9R7.d.cts +363 -0
  144. package/dist/types-ajANVzf7.d.ts +363 -0
  145. package/package.json +178 -6
@@ -0,0 +1,180 @@
1
+ // src/errors.ts
2
+ var AgentSDKError = class extends Error {
3
+ /** @internal Marker for cross-bundle identity checks */
4
+ _agentSDKError = true;
5
+ /** Machine-readable error code. Prefer values from the ErrorCode enum. */
6
+ code;
7
+ /** Whether this error is safe to retry */
8
+ retryable;
9
+ /** HTTP status code hint for error classification */
10
+ httpStatus;
11
+ constructor(message, options) {
12
+ super(message, options);
13
+ this.name = "AgentSDKError";
14
+ this.code = options?.code;
15
+ this.retryable = options?.retryable ?? false;
16
+ this.httpStatus = options?.httpStatus;
17
+ }
18
+ /** Check if an error is an AgentSDKError (works across bundled copies) */
19
+ static is(error) {
20
+ return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
21
+ }
22
+ };
23
+
24
+ // src/chat/errors.ts
25
+ var ChatError = class extends AgentSDKError {
26
+ code;
27
+ retryable;
28
+ retryAfter;
29
+ timestamp;
30
+ constructor(message, options) {
31
+ super(message, {
32
+ cause: options.cause,
33
+ code: options.code,
34
+ retryable: options.retryable
35
+ });
36
+ this.name = "ChatError";
37
+ this.code = options.code;
38
+ this.retryable = options.retryable ?? false;
39
+ this.retryAfter = options.retryAfter;
40
+ this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
41
+ }
42
+ };
43
+
44
+ // src/chat/state.ts
45
+ var StateMachine = class {
46
+ constructor(initial, transitions) {
47
+ this.initial = initial;
48
+ this.transitions = transitions;
49
+ this._current = initial;
50
+ }
51
+ _current;
52
+ /** Current state */
53
+ get current() {
54
+ return this._current;
55
+ }
56
+ /**
57
+ * Check whether transitioning to `next` is allowed from current state
58
+ * @param next - Target state to check
59
+ * @returns True if transition is allowed
60
+ */
61
+ canTransition(next) {
62
+ const allowed = this.transitions[this._current];
63
+ return allowed !== void 0 && allowed.includes(next);
64
+ }
65
+ /**
66
+ * Transition to `next` state.
67
+ * @throws ChatError(INVALID_TRANSITION) if the transition is not allowed
68
+ */
69
+ transition(next) {
70
+ if (!this.canTransition(next)) {
71
+ throw new ChatError(
72
+ `Invalid transition: ${this._current} \u2192 ${next}`,
73
+ { code: "INVALID_TRANSITION" /* INVALID_TRANSITION */ }
74
+ );
75
+ }
76
+ this._current = next;
77
+ }
78
+ /** Reset to initial state */
79
+ reset() {
80
+ this._current = this.initial;
81
+ }
82
+ };
83
+ var RUNTIME_TRANSITIONS = {
84
+ idle: ["streaming", "disposed"],
85
+ streaming: ["idle", "error", "disposed"],
86
+ error: ["idle", "disposed"],
87
+ disposed: []
88
+ };
89
+ var MESSAGE_TRANSITIONS = {
90
+ pending: ["streaming", "error", "cancelled"],
91
+ streaming: ["complete", "error", "cancelled"],
92
+ complete: [],
93
+ error: [],
94
+ cancelled: []
95
+ };
96
+ var TOOL_CALL_TRANSITIONS = {
97
+ pending: ["running", "requires_approval", "error"],
98
+ running: ["complete", "error"],
99
+ requires_approval: ["running", "denied", "error"],
100
+ complete: [],
101
+ error: [],
102
+ denied: []
103
+ };
104
+ function createRuntimeStateMachine() {
105
+ return new StateMachine("idle", RUNTIME_TRANSITIONS);
106
+ }
107
+ function createMessageStateMachine() {
108
+ return new StateMachine("pending", MESSAGE_TRANSITIONS);
109
+ }
110
+ function createToolCallStateMachine() {
111
+ return new StateMachine("pending", TOOL_CALL_TRANSITIONS);
112
+ }
113
+ var ChatReentrancyGuard = class {
114
+ _acquired = false;
115
+ /** Whether the guard is currently held */
116
+ get isAcquired() {
117
+ return this._acquired;
118
+ }
119
+ /**
120
+ * Acquire the guard. Throws if already acquired.
121
+ * @throws ChatError with code REENTRANCY
122
+ */
123
+ acquire() {
124
+ if (this._acquired) {
125
+ throw new ChatError(
126
+ "Concurrent operation detected: a send is already in progress",
127
+ { code: "REENTRANCY" /* REENTRANCY */ }
128
+ );
129
+ }
130
+ this._acquired = true;
131
+ }
132
+ /** Release the guard. Safe to call even if not acquired. */
133
+ release() {
134
+ this._acquired = false;
135
+ }
136
+ };
137
+ var ChatAbortController = class {
138
+ _controller;
139
+ _onExternalAbort;
140
+ _externalSignal;
141
+ constructor(externalSignal) {
142
+ this._controller = new AbortController();
143
+ this._externalSignal = externalSignal;
144
+ if (externalSignal) {
145
+ if (externalSignal.aborted) {
146
+ this._controller.abort(externalSignal.reason);
147
+ } else {
148
+ this._onExternalAbort = () => {
149
+ this._controller.abort(externalSignal.reason);
150
+ };
151
+ externalSignal.addEventListener("abort", this._onExternalAbort, { once: true });
152
+ }
153
+ }
154
+ }
155
+ /** The AbortSignal for this controller */
156
+ get signal() {
157
+ return this._controller.signal;
158
+ }
159
+ /** Whether the operation has been aborted */
160
+ get isAborted() {
161
+ return this._controller.signal.aborted;
162
+ }
163
+ /**
164
+ * Abort the operation.
165
+ * @param reason - Optional abort reason
166
+ */
167
+ abort(reason) {
168
+ this._controller.abort(reason);
169
+ }
170
+ /** Clean up external signal listener to prevent memory leaks */
171
+ dispose() {
172
+ if (this._onExternalAbort && this._externalSignal) {
173
+ this._externalSignal.removeEventListener("abort", this._onExternalAbort);
174
+ }
175
+ }
176
+ };
177
+
178
+ export { ChatAbortController, ChatReentrancyGuard, MESSAGE_TRANSITIONS, RUNTIME_TRANSITIONS, StateMachine, TOOL_CALL_TRANSITIONS, createMessageStateMachine, createRuntimeStateMachine, createToolCallStateMachine };
179
+ //# sourceMappingURL=state.js.map
180
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/errors.ts","../../src/chat/errors.ts","../../src/chat/state.ts"],"names":[],"mappings":"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","file":"state.js","sourcesContent":["import { ErrorCode } from \"./types/errors.js\";\n\n/** Options for constructing an AgentSDKError */\nexport interface AgentSDKErrorOptions extends ErrorOptions {\n /** Machine-readable error code */\n code?: string;\n /** Whether this error is retryable (default: false) */\n retryable?: boolean;\n /** HTTP status code hint (e.g. 401, 429, 500) */\n httpStatus?: number;\n}\n\n/** Base error class for agent-sdk.\n *\n * Use `AgentSDKError.is(err)` for reliable cross-module `instanceof` checks\n * (works across separately bundled entry points where `instanceof` may fail). */\nexport class AgentSDKError extends Error {\n /** @internal Marker for cross-bundle identity checks */\n readonly _agentSDKError = true as const;\n /** Machine-readable error code. Prefer values from the ErrorCode enum. */\n readonly code?: string;\n /** Whether this error is safe to retry */\n readonly retryable: boolean;\n /** HTTP status code hint for error classification */\n readonly httpStatus?: number;\n\n constructor(message: string, options?: AgentSDKErrorOptions) {\n super(message, options);\n this.name = \"AgentSDKError\";\n this.code = options?.code;\n this.retryable = options?.retryable ?? false;\n this.httpStatus = options?.httpStatus;\n }\n\n /** Check if an error is an AgentSDKError (works across bundled copies) */\n static is(error: unknown): error is AgentSDKError {\n return (\n error instanceof Error &&\n \"_agentSDKError\" in error &&\n (error as AgentSDKError)._agentSDKError === true\n );\n }\n}\n\n/** Thrown when agent.run() is called while already running (M8 re-entrancy guard) */\nexport class ReentrancyError extends AgentSDKError {\n constructor() {\n super(\"Agent is already running. Await the current run before starting another.\", {\n code: ErrorCode.REENTRANCY,\n });\n this.name = \"ReentrancyError\";\n }\n}\n\n/** Thrown when an operation is attempted on a disposed agent/service */\nexport class DisposedError extends AgentSDKError {\n constructor(entity: string) {\n super(`${entity} has been disposed and cannot be used.`, {\n code: ErrorCode.DISPOSED,\n });\n this.name = \"DisposedError\";\n }\n}\n\n/** Thrown when a backend is not found in the registry */\nexport class BackendNotFoundError extends AgentSDKError {\n constructor(backend: string) {\n super(\n `Unknown backend: \"${backend}\". ` +\n `Built-in: copilot, claude, vercel-ai. ` +\n `Custom: use registerBackend() first.`,\n { code: ErrorCode.BACKEND_NOT_INSTALLED },\n );\n this.name = \"BackendNotFoundError\";\n }\n}\n\n/** Thrown when a backend is already registered */\nexport class BackendAlreadyRegisteredError extends AgentSDKError {\n constructor(backend: string) {\n super(`Backend \"${backend}\" is already registered. Use a different name or unregister first.`);\n this.name = \"BackendAlreadyRegisteredError\";\n }\n}\n\n/** Thrown when subprocess management fails */\nexport class SubprocessError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, { ...options, code: ErrorCode.DEPENDENCY_MISSING });\n this.name = \"SubprocessError\";\n }\n}\n\n/** Thrown when a required peer dependency is not installed */\nexport class DependencyError extends AgentSDKError {\n public readonly packageName: string;\n\n constructor(packageName: string) {\n super(`${packageName} is not installed. Install it: npm install ${packageName}`, {\n code: ErrorCode.DEPENDENCY_MISSING,\n });\n this.name = \"DependencyError\";\n this.packageName = packageName;\n }\n}\n\n/** Thrown when an agent run is aborted */\nexport class AbortError extends AgentSDKError {\n constructor() {\n super(\"Agent run was aborted.\", { code: ErrorCode.ABORTED });\n this.name = \"AbortError\";\n }\n}\n\n/** Thrown when a tool execution fails */\nexport class ToolExecutionError extends AgentSDKError {\n public readonly toolName: string;\n\n constructor(toolName: string, message: string, options?: ErrorOptions) {\n super(`Tool \"${toolName}\" failed: ${message}`, { ...options, code: ErrorCode.TOOL_EXECUTION });\n this.name = \"ToolExecutionError\";\n this.toolName = toolName;\n }\n}\n\n/** Thrown when a stream has no activity within the configured timeout */\nexport class ActivityTimeoutError extends AgentSDKError {\n constructor(timeoutMs: number) {\n super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {\n code: ErrorCode.TIMEOUT,\n retryable: true,\n });\n this.name = \"ActivityTimeoutError\";\n }\n}\n\n/** Thrown when structured output parsing fails */\nexport class StructuredOutputError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(`Structured output error: ${message}`, { ...options, code: ErrorCode.INVALID_RESPONSE });\n this.name = \"StructuredOutputError\";\n }\n}\n","/**\n * @witqq/agent-sdk/chat/errors\n *\n * Flat error taxonomy with unified ErrorCode enum, ChatError class,\n * pattern-matching classifier, retry strategies with exponential backoff.\n * Extends the existing AgentSDKError from @witqq/agent-sdk.\n */\n\nimport { AgentSDKError } from \"../errors.js\";\nimport { ErrorCode } from \"../types/errors.js\";\n\n// ─── Re-export ErrorCode ───────────────────────────────────────\n\nexport { ErrorCode };\n\n// ─── Error Options ─────────────────────────────────────────────\n\n/** Options for constructing a ChatError */\nexport interface ChatErrorOptions {\n /** Machine-readable error code */\n code: ErrorCode;\n /** Whether this error is retryable (default: false) */\n retryable?: boolean;\n /** Retry delay hint in milliseconds */\n retryAfter?: number;\n /** Original cause, if wrapping another error */\n cause?: unknown;\n}\n\n// ─── Unified Error Class ───────────────────────────────────────\n\n/** Unified error class for all chat SDK errors */\nexport class ChatError extends AgentSDKError {\n readonly code: ErrorCode;\n readonly retryable: boolean;\n readonly retryAfter?: number;\n readonly timestamp: string;\n\n constructor(message: string, options: ChatErrorOptions) {\n super(message, {\n cause: options.cause,\n code: options.code,\n retryable: options.retryable,\n });\n this.name = \"ChatError\";\n this.code = options.code;\n this.retryable = options.retryable ?? false;\n this.retryAfter = options.retryAfter;\n this.timestamp = new Date().toISOString();\n }\n}\n\n// ─── Classification ────────────────────────────────────────────\n\n/**\n * Classify an unknown thrown value into a ChatError with the appropriate code.\n * Pattern-matches against common error shapes:\n * - Already a ChatError → returned as-is\n * - Fetch/network errors (ECONNREFUSED, ETIMEDOUT, etc.)\n * - HTTP status codes (401→AUTH_INVALID, 429→RATE_LIMIT, 5xx→PROVIDER_ERROR)\n * - Timeout patterns\n * - Zod validation errors\n * - Context overflow patterns\n * - Unknown → wrapped as ChatError with PROVIDER_ERROR\n *\n * @param error - The thrown value to classify\n * @returns ChatError with appropriate error code and retryable flag\n */\nexport function classifyError(error: unknown): ChatError {\n if (error instanceof ChatError) {\n return error;\n }\n\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n\n // Network errors\n if (isNetworkError(msg)) {\n return new ChatError(error.message, {\n code: ErrorCode.NETWORK,\n retryable: true,\n cause: error,\n });\n }\n\n // Timeout errors\n if (isTimeoutPattern(msg)) {\n return new ChatError(error.message, {\n code: ErrorCode.TIMEOUT,\n retryable: true,\n cause: error,\n });\n }\n\n // Zod validation errors\n if (isZodError(error)) {\n return new ChatError(error.message, {\n code: ErrorCode.INVALID_INPUT,\n retryable: false,\n cause: error,\n });\n }\n\n // HTTP status code errors\n const statusCode = extractStatusCode(error);\n if (statusCode !== null) {\n return classifyByStatusCode(statusCode, error);\n }\n\n // Context overflow patterns\n if (isContextOverflow(msg)) {\n return new ChatError(error.message, {\n code: ErrorCode.CONTEXT_OVERFLOW,\n retryable: false,\n cause: error,\n });\n }\n }\n\n // Unknown errors\n const message =\n error instanceof Error ? error.message : String(error);\n return new ChatError(message, {\n code: ErrorCode.PROVIDER_ERROR,\n retryable: false,\n cause: error,\n });\n}\n\n// ─── Classification Helpers ────────────────────────────────────\n\nconst NETWORK_PATTERNS = [\n \"econnrefused\",\n \"econnreset\",\n \"enotfound\",\n \"etimedout\",\n \"enetunreach\",\n \"epipe\",\n \"fetch failed\",\n \"network error\",\n \"network request failed\",\n \"failed to fetch\",\n \"dns lookup failed\",\n] as const;\n\nfunction isNetworkError(msg: string): boolean {\n return NETWORK_PATTERNS.some((p) => msg.includes(p));\n}\n\nfunction isTimeoutPattern(msg: string): boolean {\n return (\n msg.includes(\"timeout\") ||\n msg.includes(\"timed out\") ||\n msg.includes(\"deadline exceeded\") ||\n msg.includes(\"aborted due to timeout\")\n );\n}\n\nfunction isZodError(error: Error): boolean {\n return (\n error.name === \"ZodError\" ||\n (\"issues\" in error && Array.isArray((error as unknown as Record<string, unknown>).issues))\n );\n}\n\nfunction extractStatusCode(error: Error): number | null {\n const errRecord = error as unknown as Record<string, unknown>;\n if (typeof errRecord.status === \"number\") return errRecord.status;\n if (typeof errRecord.statusCode === \"number\") return errRecord.statusCode;\n\n // Check message for HTTP status codes\n const match = error.message.match(/\\b(4\\d{2}|5\\d{2})\\b/);\n return match ? parseInt(match[1], 10) : null;\n}\n\nfunction classifyByStatusCode(status: number, error: Error): ChatError {\n if (status === 401 || status === 403) {\n return new ChatError(error.message, {\n code: ErrorCode.AUTH_INVALID,\n retryable: false,\n cause: error,\n });\n }\n if (status === 429) {\n const retryAfterSeconds = extractRetryAfter(error);\n return new ChatError(error.message, {\n code: ErrorCode.RATE_LIMIT,\n retryable: true,\n retryAfter: retryAfterSeconds != null ? retryAfterSeconds * 1000 : undefined,\n cause: error,\n });\n }\n if (status >= 500) {\n return new ChatError(error.message, {\n code: ErrorCode.PROVIDER_ERROR,\n retryable: true,\n cause: error,\n });\n }\n // 4xx other than auth/rate-limit → invalid input\n if (status >= 400 && status < 500) {\n return new ChatError(error.message, {\n code: ErrorCode.INVALID_INPUT,\n retryable: false,\n cause: error,\n });\n }\n return new ChatError(error.message, {\n code: ErrorCode.NETWORK,\n retryable: true,\n cause: error,\n });\n}\n\nfunction extractRetryAfter(error: Error): number | undefined {\n const errRecord = error as unknown as Record<string, unknown>;\n if (typeof errRecord.retryAfter === \"number\") return errRecord.retryAfter;\n const match = error.message.match(/retry.after[:\\s]*(\\d+)/i);\n return match ? parseInt(match[1], 10) : undefined;\n}\n\nfunction isContextOverflow(msg: string): boolean {\n return (\n msg.includes(\"context length exceeded\") ||\n msg.includes(\"maximum context length\") ||\n msg.includes(\"context window\") ||\n msg.includes(\"token limit\") ||\n msg.includes(\"too many tokens\")\n );\n}\n\n// ─── Retry Strategy ────────────────────────────────────────────\n\n/** Strategy for computing retry delays */\nexport interface RetryStrategy {\n /** Return delay in ms for the given attempt (0-based), or null to stop */\n nextDelay(attempt: number, error: ChatError): number | null;\n}\n\n/** Options for ExponentialBackoffStrategy */\nexport interface ExponentialBackoffOptions {\n /** Base delay in ms (default: 1000) */\n baseMs?: number;\n /** Maximum delay in ms (default: 30000) */\n maxMs?: number;\n /** Maximum number of attempts (default: 3) */\n maxAttempts?: number;\n /** Jitter factor 0–1 (default: 0.1) */\n jitter?: number;\n}\n\n/** Exponential backoff with optional jitter */\nexport class ExponentialBackoffStrategy implements RetryStrategy {\n private readonly baseMs: number;\n private readonly maxMs: number;\n private readonly maxAttempts: number;\n private readonly jitter: number;\n\n constructor(options?: ExponentialBackoffOptions) {\n this.baseMs = options?.baseMs ?? 1000;\n this.maxMs = options?.maxMs ?? 30000;\n this.maxAttempts = options?.maxAttempts ?? 3;\n this.jitter = Math.max(0, Math.min(1, options?.jitter ?? 0.1));\n }\n\n nextDelay(attempt: number, error: ChatError): number | null {\n if (attempt >= this.maxAttempts) return null;\n if (!error.retryable) return null;\n\n // Rate-limit errors with retryAfter (already in ms) take priority\n if (error.code === ErrorCode.RATE_LIMIT && error.retryAfter) {\n return error.retryAfter;\n }\n\n const delay = Math.min(this.baseMs * Math.pow(2, attempt), this.maxMs);\n const jitterAmount = delay * this.jitter * (Math.random() * 2 - 1);\n return Math.max(0, Math.round(delay + jitterAmount));\n }\n}\n\n// ─── Retry Execution ───────────────────────────────────────────\n\n/** Options for withRetry execution */\nexport interface RetryOptions {\n /** Abort signal to cancel retries */\n signal?: AbortSignal;\n /** Called before each retry with the error and delay */\n onRetry?: (error: ChatError, attempt: number, delayMs: number) => void;\n}\n\n/**\n * Execute an async function with automatic retries using the provided strategy.\n * Respects ChatError.retryable and ChatError.retryAfter.\n * Classifies non-ChatError errors before deciding on retry.\n *\n * @param fn - Async function to execute\n * @param strategy - Retry strategy providing delay calculations\n * @param options - Optional abort signal and retry callback\n * @returns Result of fn on success\n * @throws ChatError when all retries exhausted or error is non-retryable\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n strategy: RetryStrategy,\n options?: RetryOptions,\n): Promise<T> {\n let attempt = 0;\n\n for (;;) {\n try {\n return await fn();\n } catch (raw) {\n const error = classifyError(raw);\n const delay = strategy.nextDelay(attempt, error);\n\n if (delay === null) {\n throw error;\n }\n\n if (options?.signal?.aborted) {\n throw error;\n }\n\n options?.onRetry?.(error, attempt, delay);\n\n await sleep(delay, options?.signal);\n attempt++;\n }\n }\n}\n\n/**\n * Type guard: check if an error is retryable\n * @param error - The error to check\n * @returns True if error is a retryable ChatError\n */\nexport function isRetryable(error: unknown): boolean {\n if (error instanceof ChatError) {\n return error.retryable;\n }\n const classified = classifyError(error);\n return classified.retryable;\n}\n\n// ─── Internal Helpers ──────────────────────────────────────────\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(new ChatError(\"Retry aborted\", { code: ErrorCode.ABORTED }));\n return;\n }\n\n const timer = setTimeout(resolve, ms);\n\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n reject(new ChatError(\"Retry aborted\", { code: ErrorCode.ABORTED }));\n },\n { once: true },\n );\n });\n}\n","/**\n * @witqq/agent-sdk/chat/state\n *\n * Validated state machines for runtime, message, and tool-call lifecycles.\n * Generic StateMachine<S> with declarative transition maps.\n */\n\nimport type { RuntimeStatus, MessageStatus, ToolCallStatus } from \"./core.js\";\nimport { ChatError, ErrorCode } from \"./errors.js\";\n\n// ─── Generic State Machine ─────────────────────────────────────\n\n/** Map of allowed transitions: current state → set of valid next states */\nexport type TransitionMap<S extends string> = Readonly<Record<S, readonly S[]>>;\n\n/**\n * Generic validated state machine.\n * Enforces that every transition is declared in the transition map.\n * Throws ChatError(INVALID_TRANSITION) on illegal moves.\n */\nexport class StateMachine<S extends string> {\n private _current: S;\n\n constructor(\n readonly initial: S,\n readonly transitions: TransitionMap<S>,\n ) {\n this._current = initial;\n }\n\n /** Current state */\n get current(): S {\n return this._current;\n }\n\n /**\n * Check whether transitioning to `next` is allowed from current state\n * @param next - Target state to check\n * @returns True if transition is allowed\n */\n canTransition(next: S): boolean {\n const allowed = this.transitions[this._current];\n return allowed !== undefined && allowed.includes(next);\n }\n\n /**\n * Transition to `next` state.\n * @throws ChatError(INVALID_TRANSITION) if the transition is not allowed\n */\n transition(next: S): void {\n if (!this.canTransition(next)) {\n throw new ChatError(\n `Invalid transition: ${this._current} → ${next}`,\n { code: ErrorCode.INVALID_TRANSITION },\n );\n }\n this._current = next;\n }\n\n /** Reset to initial state */\n reset(): void {\n this._current = this.initial;\n }\n}\n\n// ─── Transition Maps ───────────────────────────────────────────\n\n/** Allowed transitions for RuntimeStatus (idle → streaming/disposed, etc.) */\nexport const RUNTIME_TRANSITIONS: TransitionMap<RuntimeStatus> = {\n idle: [\"streaming\", \"disposed\"],\n streaming: [\"idle\", \"error\", \"disposed\"],\n error: [\"idle\", \"disposed\"],\n disposed: [],\n};\n\n/** Allowed transitions for MessageStatus (pending → streaming → complete, etc.) */\nexport const MESSAGE_TRANSITIONS: TransitionMap<MessageStatus> = {\n pending: [\"streaming\", \"error\", \"cancelled\"],\n streaming: [\"complete\", \"error\", \"cancelled\"],\n complete: [],\n error: [],\n cancelled: [],\n};\n\n/** Allowed transitions for ToolCallStatus (pending → running → complete, etc.) */\nexport const TOOL_CALL_TRANSITIONS: TransitionMap<ToolCallStatus> = {\n pending: [\"running\", \"requires_approval\", \"error\"],\n running: [\"complete\", \"error\"],\n requires_approval: [\"running\", \"denied\", \"error\"],\n complete: [],\n error: [],\n denied: [],\n};\n\n// ─── Pre-configured Factories ──────────────────────────────────\n\n/** Create a RuntimeStatus state machine starting at \"idle\" */\nexport function createRuntimeStateMachine(): StateMachine<RuntimeStatus> {\n return new StateMachine<RuntimeStatus>(\"idle\", RUNTIME_TRANSITIONS);\n}\n\n/** Create a MessageStatus state machine starting at \"pending\" */\nexport function createMessageStateMachine(): StateMachine<MessageStatus> {\n return new StateMachine<MessageStatus>(\"pending\", MESSAGE_TRANSITIONS);\n}\n\n/** Create a ToolCallStatus state machine starting at \"pending\" */\nexport function createToolCallStateMachine(): StateMachine<ToolCallStatus> {\n return new StateMachine<ToolCallStatus>(\"pending\", TOOL_CALL_TRANSITIONS);\n}\n\n// ─── Reentrancy Guard ──────────────────────────────────────────\n\n/**\n * Guards against concurrent send() calls in a chat runtime.\n * acquire() before work, release() after (use try/finally).\n * Throws ChatError(REENTRANCY) if already acquired.\n */\nexport class ChatReentrancyGuard {\n private _acquired = false;\n\n /** Whether the guard is currently held */\n get isAcquired(): boolean {\n return this._acquired;\n }\n\n /**\n * Acquire the guard. Throws if already acquired.\n * @throws ChatError with code REENTRANCY\n */\n acquire(): void {\n if (this._acquired) {\n throw new ChatError(\n \"Concurrent operation detected: a send is already in progress\",\n { code: ErrorCode.REENTRANCY },\n );\n }\n this._acquired = true;\n }\n\n /** Release the guard. Safe to call even if not acquired. */\n release(): void {\n this._acquired = false;\n }\n}\n\n// ─── Abort Controller ──────────────────────────────────────────\n\n/**\n * Abort controller with external signal linking.\n * Wraps an AbortController and optionally links an external AbortSignal\n * so aborting either side cancels the operation.\n */\nexport class ChatAbortController {\n private readonly _controller: AbortController;\n private readonly _onExternalAbort?: () => void;\n private readonly _externalSignal?: AbortSignal;\n\n constructor(externalSignal?: AbortSignal) {\n this._controller = new AbortController();\n this._externalSignal = externalSignal;\n\n if (externalSignal) {\n // If external signal already aborted, abort immediately\n if (externalSignal.aborted) {\n this._controller.abort(externalSignal.reason);\n } else {\n // Link: external abort → our controller\n this._onExternalAbort = () => {\n this._controller.abort(externalSignal.reason);\n };\n externalSignal.addEventListener(\"abort\", this._onExternalAbort, { once: true });\n }\n }\n }\n\n /** The AbortSignal for this controller */\n get signal(): AbortSignal {\n return this._controller.signal;\n }\n\n /** Whether the operation has been aborted */\n get isAborted(): boolean {\n return this._controller.signal.aborted;\n }\n\n /**\n * Abort the operation.\n * @param reason - Optional abort reason\n */\n abort(reason?: unknown): void {\n this._controller.abort(reason);\n }\n\n /** Clean up external signal listener to prevent memory leaks */\n dispose(): void {\n if (this._onExternalAbort && this._externalSignal) {\n this._externalSignal.removeEventListener(\"abort\", this._onExternalAbort);\n }\n }\n}\n"]}
@@ -0,0 +1,249 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+
6
+ // src/chat/storage.ts
7
+
8
+ // src/errors.ts
9
+ var AgentSDKError = class extends Error {
10
+ /** @internal Marker for cross-bundle identity checks */
11
+ _agentSDKError = true;
12
+ /** Machine-readable error code. Prefer values from the ErrorCode enum. */
13
+ code;
14
+ /** Whether this error is safe to retry */
15
+ retryable;
16
+ /** HTTP status code hint for error classification */
17
+ httpStatus;
18
+ constructor(message, options) {
19
+ super(message, options);
20
+ this.name = "AgentSDKError";
21
+ this.code = options?.code;
22
+ this.retryable = options?.retryable ?? false;
23
+ this.httpStatus = options?.httpStatus;
24
+ }
25
+ /** Check if an error is an AgentSDKError (works across bundled copies) */
26
+ static is(error) {
27
+ return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
28
+ }
29
+ };
30
+
31
+ // src/chat/storage.ts
32
+ var StorageError = class extends AgentSDKError {
33
+ /** Machine-readable error code from the unified ErrorCode enum */
34
+ code;
35
+ constructor(message, code) {
36
+ super(message);
37
+ this.name = "StorageError";
38
+ this.code = code;
39
+ }
40
+ };
41
+ var InMemoryStorage = class {
42
+ data = /* @__PURE__ */ new Map();
43
+ /** @inheritdoc */
44
+ async get(key) {
45
+ const item = this.data.get(key);
46
+ return item !== void 0 ? structuredClone(item) : null;
47
+ }
48
+ /** @inheritdoc */
49
+ async list(options) {
50
+ let items = Array.from(this.data.values()).map((item) => structuredClone(item));
51
+ if (options?.filter) {
52
+ items = items.filter(options.filter);
53
+ }
54
+ if (options?.sort) {
55
+ items.sort(options.sort);
56
+ }
57
+ if (options?.offset !== void 0) {
58
+ items = items.slice(options.offset);
59
+ }
60
+ if (options?.limit !== void 0) {
61
+ items = items.slice(0, options.limit);
62
+ }
63
+ return items;
64
+ }
65
+ /** @inheritdoc */
66
+ async create(key, item) {
67
+ if (this.data.has(key)) {
68
+ throw new StorageError(
69
+ `Item with key "${key}" already exists`,
70
+ "STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
71
+ );
72
+ }
73
+ this.data.set(key, structuredClone(item));
74
+ }
75
+ /** @inheritdoc */
76
+ async update(key, item) {
77
+ if (!this.data.has(key)) {
78
+ throw new StorageError(
79
+ `Item with key "${key}" not found`,
80
+ "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
81
+ );
82
+ }
83
+ this.data.set(key, structuredClone(item));
84
+ }
85
+ /** @inheritdoc */
86
+ async delete(key) {
87
+ if (!this.data.has(key)) {
88
+ throw new StorageError(
89
+ `Item with key "${key}" not found`,
90
+ "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
91
+ );
92
+ }
93
+ this.data.delete(key);
94
+ }
95
+ /** @inheritdoc */
96
+ async has(key) {
97
+ return this.data.has(key);
98
+ }
99
+ /** @inheritdoc */
100
+ async count() {
101
+ return this.data.size;
102
+ }
103
+ /** @inheritdoc */
104
+ async clear() {
105
+ this.data.clear();
106
+ }
107
+ };
108
+ var FileStorage = class {
109
+ directory;
110
+ extension;
111
+ constructor(options) {
112
+ this.directory = options.directory;
113
+ this.extension = options.extension ?? ".json";
114
+ this.ensureDirectory();
115
+ }
116
+ /** @inheritdoc */
117
+ async get(key) {
118
+ const filePath = this.keyToPath(key);
119
+ if (!fs.existsSync(filePath)) {
120
+ return null;
121
+ }
122
+ return this.readFile(filePath);
123
+ }
124
+ /** @inheritdoc */
125
+ async list(options) {
126
+ this.ensureDirectory();
127
+ const files = fs.readdirSync(this.directory).filter(
128
+ (f) => f.endsWith(this.extension)
129
+ );
130
+ let items = [];
131
+ for (const file of files) {
132
+ const item = this.readFile(path.join(this.directory, file));
133
+ items.push(item);
134
+ }
135
+ if (options?.filter) {
136
+ items = items.filter(options.filter);
137
+ }
138
+ if (options?.sort) {
139
+ items.sort(options.sort);
140
+ }
141
+ if (options?.offset !== void 0) {
142
+ items = items.slice(options.offset);
143
+ }
144
+ if (options?.limit !== void 0) {
145
+ items = items.slice(0, options.limit);
146
+ }
147
+ return items;
148
+ }
149
+ /** @inheritdoc */
150
+ async create(key, item) {
151
+ const filePath = this.keyToPath(key);
152
+ if (fs.existsSync(filePath)) {
153
+ throw new StorageError(
154
+ `Item with key "${key}" already exists`,
155
+ "STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
156
+ );
157
+ }
158
+ this.writeFile(filePath, item);
159
+ }
160
+ /** @inheritdoc */
161
+ async update(key, item) {
162
+ const filePath = this.keyToPath(key);
163
+ if (!fs.existsSync(filePath)) {
164
+ throw new StorageError(
165
+ `Item with key "${key}" not found`,
166
+ "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
167
+ );
168
+ }
169
+ this.writeFile(filePath, item);
170
+ }
171
+ /** @inheritdoc */
172
+ async delete(key) {
173
+ const filePath = this.keyToPath(key);
174
+ if (!fs.existsSync(filePath)) {
175
+ throw new StorageError(
176
+ `Item with key "${key}" not found`,
177
+ "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
178
+ );
179
+ }
180
+ fs.unlinkSync(filePath);
181
+ }
182
+ /** @inheritdoc */
183
+ async has(key) {
184
+ return fs.existsSync(this.keyToPath(key));
185
+ }
186
+ /** @inheritdoc */
187
+ async count() {
188
+ this.ensureDirectory();
189
+ return fs.readdirSync(this.directory).filter(
190
+ (f) => f.endsWith(this.extension)
191
+ ).length;
192
+ }
193
+ /** @inheritdoc */
194
+ async clear() {
195
+ this.ensureDirectory();
196
+ const files = fs.readdirSync(this.directory).filter(
197
+ (f) => f.endsWith(this.extension)
198
+ );
199
+ for (const file of files) {
200
+ fs.unlinkSync(path.join(this.directory, file));
201
+ }
202
+ }
203
+ keyToPath(key) {
204
+ const safeKey = key.replace(
205
+ /[^a-zA-Z0-9_-]/g,
206
+ (c) => "%" + c.charCodeAt(0).toString(16).padStart(2, "0")
207
+ );
208
+ return path.join(this.directory, `${safeKey}${this.extension}`);
209
+ }
210
+ ensureDirectory() {
211
+ if (!fs.existsSync(this.directory)) {
212
+ fs.mkdirSync(this.directory, { recursive: true });
213
+ }
214
+ }
215
+ readFile(filePath) {
216
+ try {
217
+ const content = fs.readFileSync(filePath, "utf-8");
218
+ return JSON.parse(content);
219
+ } catch (error) {
220
+ if (error instanceof SyntaxError) {
221
+ throw new StorageError(
222
+ `Failed to parse file: ${filePath}`,
223
+ "STORAGE_SERIALIZATION_ERROR" /* STORAGE_SERIALIZATION_ERROR */
224
+ );
225
+ }
226
+ throw new StorageError(
227
+ `Failed to read file: ${filePath}`,
228
+ "STORAGE_IO_ERROR" /* STORAGE_IO_ERROR */
229
+ );
230
+ }
231
+ }
232
+ writeFile(filePath, item) {
233
+ try {
234
+ const content = JSON.stringify(item, null, 2);
235
+ fs.writeFileSync(filePath, content, "utf-8");
236
+ } catch {
237
+ throw new StorageError(
238
+ `Failed to write file: ${filePath}`,
239
+ "STORAGE_IO_ERROR" /* STORAGE_IO_ERROR */
240
+ );
241
+ }
242
+ }
243
+ };
244
+
245
+ exports.FileStorage = FileStorage;
246
+ exports.InMemoryStorage = InMemoryStorage;
247
+ exports.StorageError = StorageError;
248
+ //# sourceMappingURL=storage.cjs.map
249
+ //# sourceMappingURL=storage.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/errors.ts","../../src/chat/storage.ts"],"names":["existsSync","readdirSync","join","unlinkSync","mkdirSync","readFileSync","writeFileSync"],"mappings":"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","file":"storage.cjs","sourcesContent":["import { ErrorCode } from \"./types/errors.js\";\n\n/** Options for constructing an AgentSDKError */\nexport interface AgentSDKErrorOptions extends ErrorOptions {\n /** Machine-readable error code */\n code?: string;\n /** Whether this error is retryable (default: false) */\n retryable?: boolean;\n /** HTTP status code hint (e.g. 401, 429, 500) */\n httpStatus?: number;\n}\n\n/** Base error class for agent-sdk.\n *\n * Use `AgentSDKError.is(err)` for reliable cross-module `instanceof` checks\n * (works across separately bundled entry points where `instanceof` may fail). */\nexport class AgentSDKError extends Error {\n /** @internal Marker for cross-bundle identity checks */\n readonly _agentSDKError = true as const;\n /** Machine-readable error code. Prefer values from the ErrorCode enum. */\n readonly code?: string;\n /** Whether this error is safe to retry */\n readonly retryable: boolean;\n /** HTTP status code hint for error classification */\n readonly httpStatus?: number;\n\n constructor(message: string, options?: AgentSDKErrorOptions) {\n super(message, options);\n this.name = \"AgentSDKError\";\n this.code = options?.code;\n this.retryable = options?.retryable ?? false;\n this.httpStatus = options?.httpStatus;\n }\n\n /** Check if an error is an AgentSDKError (works across bundled copies) */\n static is(error: unknown): error is AgentSDKError {\n return (\n error instanceof Error &&\n \"_agentSDKError\" in error &&\n (error as AgentSDKError)._agentSDKError === true\n );\n }\n}\n\n/** Thrown when agent.run() is called while already running (M8 re-entrancy guard) */\nexport class ReentrancyError extends AgentSDKError {\n constructor() {\n super(\"Agent is already running. Await the current run before starting another.\", {\n code: ErrorCode.REENTRANCY,\n });\n this.name = \"ReentrancyError\";\n }\n}\n\n/** Thrown when an operation is attempted on a disposed agent/service */\nexport class DisposedError extends AgentSDKError {\n constructor(entity: string) {\n super(`${entity} has been disposed and cannot be used.`, {\n code: ErrorCode.DISPOSED,\n });\n this.name = \"DisposedError\";\n }\n}\n\n/** Thrown when a backend is not found in the registry */\nexport class BackendNotFoundError extends AgentSDKError {\n constructor(backend: string) {\n super(\n `Unknown backend: \"${backend}\". ` +\n `Built-in: copilot, claude, vercel-ai. ` +\n `Custom: use registerBackend() first.`,\n { code: ErrorCode.BACKEND_NOT_INSTALLED },\n );\n this.name = \"BackendNotFoundError\";\n }\n}\n\n/** Thrown when a backend is already registered */\nexport class BackendAlreadyRegisteredError extends AgentSDKError {\n constructor(backend: string) {\n super(`Backend \"${backend}\" is already registered. Use a different name or unregister first.`);\n this.name = \"BackendAlreadyRegisteredError\";\n }\n}\n\n/** Thrown when subprocess management fails */\nexport class SubprocessError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, { ...options, code: ErrorCode.DEPENDENCY_MISSING });\n this.name = \"SubprocessError\";\n }\n}\n\n/** Thrown when a required peer dependency is not installed */\nexport class DependencyError extends AgentSDKError {\n public readonly packageName: string;\n\n constructor(packageName: string) {\n super(`${packageName} is not installed. Install it: npm install ${packageName}`, {\n code: ErrorCode.DEPENDENCY_MISSING,\n });\n this.name = \"DependencyError\";\n this.packageName = packageName;\n }\n}\n\n/** Thrown when an agent run is aborted */\nexport class AbortError extends AgentSDKError {\n constructor() {\n super(\"Agent run was aborted.\", { code: ErrorCode.ABORTED });\n this.name = \"AbortError\";\n }\n}\n\n/** Thrown when a tool execution fails */\nexport class ToolExecutionError extends AgentSDKError {\n public readonly toolName: string;\n\n constructor(toolName: string, message: string, options?: ErrorOptions) {\n super(`Tool \"${toolName}\" failed: ${message}`, { ...options, code: ErrorCode.TOOL_EXECUTION });\n this.name = \"ToolExecutionError\";\n this.toolName = toolName;\n }\n}\n\n/** Thrown when a stream has no activity within the configured timeout */\nexport class ActivityTimeoutError extends AgentSDKError {\n constructor(timeoutMs: number) {\n super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {\n code: ErrorCode.TIMEOUT,\n retryable: true,\n });\n this.name = \"ActivityTimeoutError\";\n }\n}\n\n/** Thrown when structured output parsing fails */\nexport class StructuredOutputError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(`Structured output error: ${message}`, { ...options, code: ErrorCode.INVALID_RESPONSE });\n this.name = \"StructuredOutputError\";\n }\n}\n","/**\n * @witqq/agent-sdk/chat/storage\n *\n * Generic storage adapter layer with pluggable backends.\n * Provides CRUD operations for any data type via `IStorageAdapter<T>`.\n * Implementations: `InMemoryStorage` (Map-based) and `FileStorage` (JSON files).\n */\n\nimport { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { AgentSDKError } from \"../errors.js\";\nimport { ErrorCode } from \"../types/errors.js\";\n\n// ─── Storage Errors ────────────────────────────────────────────\n\n/**\n * Error thrown by storage operations.\n *\n * @example\n * ```typescript\n * try {\n * await store.get(\"missing-id\");\n * } catch (e) {\n * if (e instanceof StorageError && e.code === ErrorCode.STORAGE_NOT_FOUND) {\n * // handle missing item\n * }\n * }\n * ```\n */\nexport class StorageError extends AgentSDKError {\n /** Machine-readable error code from the unified ErrorCode enum */\n readonly code: StorageErrorCode;\n\n constructor(message: string, code: StorageErrorCode) {\n super(message);\n this.name = \"StorageError\";\n this.code = code;\n }\n}\n\n/** Storage-specific subset of ErrorCode */\nexport type StorageErrorCode =\n | ErrorCode.STORAGE_NOT_FOUND\n | ErrorCode.STORAGE_DUPLICATE_KEY\n | ErrorCode.STORAGE_IO_ERROR\n | ErrorCode.STORAGE_SERIALIZATION_ERROR;\n\n// ─── Storage Adapter Interface ─────────────────────────────────\n\n/**\n * Options for listing stored items.\n *\n * @typeParam T - The type of stored items\n */\nexport interface ListOptions<T> {\n /** Filter predicate — return `true` to include the item */\n filter?: (item: T) => boolean;\n /** Sort comparator — standard Array.sort semantics */\n sort?: (a: T, b: T) => number;\n /** Maximum number of items to return */\n limit?: number;\n /** Number of items to skip (for pagination) */\n offset?: number;\n}\n\n/**\n * Generic storage adapter for CRUD operations on any data type.\n * Items are identified by a string key.\n *\n * @typeParam T - The type of stored items\n *\n * @example\n * ```typescript\n * const store: IStorageAdapter<{ name: string }> = new InMemoryStorage();\n * await store.create(\"key1\", { name: \"Alice\" });\n * const item = await store.get(\"key1\"); // { name: \"Alice\" }\n * ```\n */\nexport interface IStorageAdapter<T> {\n /**\n * Retrieve an item by key.\n * @param key - Unique identifier\n * @returns The item, or `null` if not found\n */\n get(key: string): Promise<T | null>;\n\n /**\n * List items with optional filtering, sorting, and pagination.\n * @param options - Filter, sort, limit, offset options\n * @returns Array of matching items\n */\n list(options?: ListOptions<T>): Promise<T[]>;\n\n /**\n * Create a new item. Throws `StorageError` with code `DUPLICATE_KEY` if key exists.\n * @param key - Unique identifier\n * @param item - Data to store\n */\n create(key: string, item: T): Promise<void>;\n\n /**\n * Update an existing item. Throws `StorageError` with code `NOT_FOUND` if key missing.\n * @param key - Unique identifier\n * @param item - Updated data\n */\n update(key: string, item: T): Promise<void>;\n\n /**\n * Delete an item by key. Throws `StorageError` with code `NOT_FOUND` if key missing.\n * @param key - Unique identifier\n */\n delete(key: string): Promise<void>;\n\n /**\n * Check whether a key exists.\n * @param key - Unique identifier\n * @returns `true` if key exists\n */\n has(key: string): Promise<boolean>;\n\n /**\n * Return the number of stored items.\n * @returns Count of items\n */\n count(): Promise<number>;\n\n /**\n * Remove all items from storage.\n */\n clear(): Promise<void>;\n\n /**\n * Release any resources held by this adapter (DB connections, file handles).\n * Optional — adapters that don't hold resources need not implement this.\n */\n dispose?(): Promise<void>;\n}\n\n// ─── InMemoryStorage ───────────────────────────────────────────\n\n/**\n * In-memory storage adapter backed by a `Map`.\n * Suitable for development, testing, and short-lived processes.\n * Data is lost when the process exits.\n *\n * @typeParam T - The type of stored items\n *\n * @example\n * ```typescript\n * const store = new InMemoryStorage<{ name: string }>();\n * await store.create(\"k1\", { name: \"Alice\" });\n * await store.create(\"k2\", { name: \"Bob\" });\n * const items = await store.list({ filter: i => i.name.startsWith(\"A\") });\n * // [{ name: \"Alice\" }]\n * ```\n */\nexport class InMemoryStorage<T> implements IStorageAdapter<T> {\n private readonly data = new Map<string, T>();\n\n /** @inheritdoc */\n async get(key: string): Promise<T | null> {\n const item = this.data.get(key);\n return item !== undefined ? structuredClone(item) : null;\n }\n\n /** @inheritdoc */\n async list(options?: ListOptions<T>): Promise<T[]> {\n let items = Array.from(this.data.values()).map((item) => structuredClone(item));\n\n if (options?.filter) {\n items = items.filter(options.filter);\n }\n if (options?.sort) {\n items.sort(options.sort);\n }\n if (options?.offset !== undefined) {\n items = items.slice(options.offset);\n }\n if (options?.limit !== undefined) {\n items = items.slice(0, options.limit);\n }\n\n return items;\n }\n\n /** @inheritdoc */\n async create(key: string, item: T): Promise<void> {\n if (this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" already exists`,\n ErrorCode.STORAGE_DUPLICATE_KEY,\n );\n }\n this.data.set(key, structuredClone(item));\n }\n\n /** @inheritdoc */\n async update(key: string, item: T): Promise<void> {\n if (!this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.data.set(key, structuredClone(item));\n }\n\n /** @inheritdoc */\n async delete(key: string): Promise<void> {\n if (!this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.data.delete(key);\n }\n\n /** @inheritdoc */\n async has(key: string): Promise<boolean> {\n return this.data.has(key);\n }\n\n /** @inheritdoc */\n async count(): Promise<number> {\n return this.data.size;\n }\n\n /** @inheritdoc */\n async clear(): Promise<void> {\n this.data.clear();\n }\n}\n\n// ─── FileStorage ───────────────────────────────────────────────\n\n/**\n * Options for configuring `FileStorage`.\n */\nexport interface FileStorageOptions {\n /** Directory path where JSON files are stored */\n directory: string;\n /** File extension (default: `.json`) */\n extension?: string;\n}\n\n/**\n * File-based storage adapter that persists each item as a JSON file.\n * Suitable for local applications, CLI tools, and development.\n * Creates the storage directory if it doesn't exist.\n *\n * @typeParam T - The type of stored items (must be JSON-serializable)\n *\n * @example\n * ```typescript\n * const store = new FileStorage<ChatSession>({\n * directory: \"./data/sessions\",\n * });\n * await store.create(\"session-1\", mySession);\n * ```\n */\nexport class FileStorage<T> implements IStorageAdapter<T> {\n private readonly directory: string;\n private readonly extension: string;\n\n constructor(options: FileStorageOptions) {\n this.directory = options.directory;\n this.extension = options.extension ?? \".json\";\n this.ensureDirectory();\n }\n\n /** @inheritdoc */\n async get(key: string): Promise<T | null> {\n const filePath = this.keyToPath(key);\n if (!existsSync(filePath)) {\n return null;\n }\n return this.readFile(filePath);\n }\n\n /** @inheritdoc */\n async list(options?: ListOptions<T>): Promise<T[]> {\n this.ensureDirectory();\n const files = readdirSync(this.directory).filter((f) =>\n f.endsWith(this.extension),\n );\n\n let items: T[] = [];\n for (const file of files) {\n const item = this.readFile(join(this.directory, file));\n items.push(item);\n }\n\n if (options?.filter) {\n items = items.filter(options.filter);\n }\n if (options?.sort) {\n items.sort(options.sort);\n }\n if (options?.offset !== undefined) {\n items = items.slice(options.offset);\n }\n if (options?.limit !== undefined) {\n items = items.slice(0, options.limit);\n }\n\n return items;\n }\n\n /** @inheritdoc */\n async create(key: string, item: T): Promise<void> {\n const filePath = this.keyToPath(key);\n if (existsSync(filePath)) {\n throw new StorageError(\n `Item with key \"${key}\" already exists`,\n ErrorCode.STORAGE_DUPLICATE_KEY,\n );\n }\n this.writeFile(filePath, item);\n }\n\n /** @inheritdoc */\n async update(key: string, item: T): Promise<void> {\n const filePath = this.keyToPath(key);\n if (!existsSync(filePath)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.writeFile(filePath, item);\n }\n\n /** @inheritdoc */\n async delete(key: string): Promise<void> {\n const filePath = this.keyToPath(key);\n if (!existsSync(filePath)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n unlinkSync(filePath);\n }\n\n /** @inheritdoc */\n async has(key: string): Promise<boolean> {\n return existsSync(this.keyToPath(key));\n }\n\n /** @inheritdoc */\n async count(): Promise<number> {\n this.ensureDirectory();\n return readdirSync(this.directory).filter((f) =>\n f.endsWith(this.extension),\n ).length;\n }\n\n /** @inheritdoc */\n async clear(): Promise<void> {\n this.ensureDirectory();\n const files = readdirSync(this.directory).filter((f) =>\n f.endsWith(this.extension),\n );\n for (const file of files) {\n unlinkSync(join(this.directory, file));\n }\n }\n\n private keyToPath(key: string): string {\n const safeKey = key.replace(/[^a-zA-Z0-9_-]/g, (c) =>\n \"%\" + c.charCodeAt(0).toString(16).padStart(2, \"0\"),\n );\n return join(this.directory, `${safeKey}${this.extension}`);\n }\n\n private ensureDirectory(): void {\n if (!existsSync(this.directory)) {\n mkdirSync(this.directory, { recursive: true });\n }\n }\n\n private readFile(filePath: string): T {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new StorageError(\n `Failed to parse file: ${filePath}`,\n ErrorCode.STORAGE_SERIALIZATION_ERROR,\n );\n }\n throw new StorageError(\n `Failed to read file: ${filePath}`,\n ErrorCode.STORAGE_IO_ERROR,\n );\n }\n }\n\n private writeFile(filePath: string, item: T): void {\n try {\n const content = JSON.stringify(item, null, 2);\n writeFileSync(filePath, content, \"utf-8\");\n } catch {\n throw new StorageError(\n `Failed to write file: ${filePath}`,\n ErrorCode.STORAGE_IO_ERROR,\n );\n }\n }\n}\n"]}