@witqq/agent-sdk 0.8.0 → 0.9.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 (113) hide show
  1. package/dist/{agent-DxY68NZL.d.cts → agent-C6H2CgJA.d.cts} +2 -0
  2. package/dist/{agent-CW9XbmG_.d.ts → agent-F7oB6eKp.d.ts} +2 -0
  3. package/dist/backends/claude.cjs.map +1 -1
  4. package/dist/backends/claude.d.cts +2 -2
  5. package/dist/backends/claude.d.ts +2 -2
  6. package/dist/backends/claude.js.map +1 -1
  7. package/dist/backends/copilot.cjs +8 -15
  8. package/dist/backends/copilot.cjs.map +1 -1
  9. package/dist/backends/copilot.d.cts +2 -2
  10. package/dist/backends/copilot.d.ts +2 -2
  11. package/dist/backends/copilot.js +8 -15
  12. package/dist/backends/copilot.js.map +1 -1
  13. package/dist/backends/mock-llm.cjs +719 -0
  14. package/dist/backends/mock-llm.cjs.map +1 -0
  15. package/dist/backends/mock-llm.d.cts +37 -0
  16. package/dist/backends/mock-llm.d.ts +37 -0
  17. package/dist/backends/mock-llm.js +717 -0
  18. package/dist/backends/mock-llm.js.map +1 -0
  19. package/dist/backends/vercel-ai.cjs +8 -1
  20. package/dist/backends/vercel-ai.cjs.map +1 -1
  21. package/dist/backends/vercel-ai.d.cts +2 -2
  22. package/dist/backends/vercel-ai.d.ts +2 -2
  23. package/dist/backends/vercel-ai.js +8 -1
  24. package/dist/backends/vercel-ai.js.map +1 -1
  25. package/dist/backends-Cno0gZjy.d.cts +114 -0
  26. package/dist/backends-Cno0gZjy.d.ts +114 -0
  27. package/dist/chat/accumulator.cjs.map +1 -1
  28. package/dist/chat/accumulator.d.cts +2 -2
  29. package/dist/chat/accumulator.d.ts +2 -2
  30. package/dist/chat/accumulator.js.map +1 -1
  31. package/dist/chat/backends.cjs +350 -77
  32. package/dist/chat/backends.cjs.map +1 -1
  33. package/dist/chat/backends.d.cts +7 -7
  34. package/dist/chat/backends.d.ts +7 -7
  35. package/dist/chat/backends.js +349 -78
  36. package/dist/chat/backends.js.map +1 -1
  37. package/dist/chat/context.d.cts +2 -2
  38. package/dist/chat/context.d.ts +2 -2
  39. package/dist/chat/core.cjs +35 -25
  40. package/dist/chat/core.cjs.map +1 -1
  41. package/dist/chat/core.d.cts +15 -5
  42. package/dist/chat/core.d.ts +15 -5
  43. package/dist/chat/core.js +35 -26
  44. package/dist/chat/core.js.map +1 -1
  45. package/dist/chat/events.d.cts +2 -2
  46. package/dist/chat/events.d.ts +2 -2
  47. package/dist/chat/index.cjs +418 -122
  48. package/dist/chat/index.cjs.map +1 -1
  49. package/dist/chat/index.d.cts +7 -7
  50. package/dist/chat/index.d.ts +7 -7
  51. package/dist/chat/index.js +418 -124
  52. package/dist/chat/index.js.map +1 -1
  53. package/dist/chat/react.cjs +216 -12
  54. package/dist/chat/react.cjs.map +1 -1
  55. package/dist/chat/react.d.cts +78 -4
  56. package/dist/chat/react.d.ts +78 -4
  57. package/dist/chat/react.js +215 -13
  58. package/dist/chat/react.js.map +1 -1
  59. package/dist/chat/runtime.cjs +6 -2
  60. package/dist/chat/runtime.cjs.map +1 -1
  61. package/dist/chat/runtime.d.cts +2 -2
  62. package/dist/chat/runtime.d.ts +2 -2
  63. package/dist/chat/runtime.js +6 -2
  64. package/dist/chat/runtime.js.map +1 -1
  65. package/dist/chat/server.cjs +15 -5
  66. package/dist/chat/server.cjs.map +1 -1
  67. package/dist/chat/server.d.cts +3 -3
  68. package/dist/chat/server.d.ts +3 -3
  69. package/dist/chat/server.js +15 -5
  70. package/dist/chat/server.js.map +1 -1
  71. package/dist/chat/sessions.cjs +39 -23
  72. package/dist/chat/sessions.cjs.map +1 -1
  73. package/dist/chat/sessions.d.cts +2 -2
  74. package/dist/chat/sessions.d.ts +2 -2
  75. package/dist/chat/sessions.js +40 -24
  76. package/dist/chat/sessions.js.map +1 -1
  77. package/dist/chat/sqlite.cjs +95 -0
  78. package/dist/chat/sqlite.cjs.map +1 -1
  79. package/dist/chat/sqlite.d.cts +39 -3
  80. package/dist/chat/sqlite.d.ts +39 -3
  81. package/dist/chat/sqlite.js +93 -1
  82. package/dist/chat/sqlite.js.map +1 -1
  83. package/dist/chat/state.d.cts +2 -2
  84. package/dist/chat/state.d.ts +2 -2
  85. package/dist/chat/storage.cjs +39 -23
  86. package/dist/chat/storage.cjs.map +1 -1
  87. package/dist/chat/storage.d.cts +7 -3
  88. package/dist/chat/storage.d.ts +7 -3
  89. package/dist/chat/storage.js +40 -24
  90. package/dist/chat/storage.js.map +1 -1
  91. package/dist/{in-process-transport-C1JnJGVR.d.ts → in-process-transport-7EIit9Xk.d.ts} +51 -17
  92. package/dist/{in-process-transport-C7DSqPyX.d.cts → in-process-transport-Ct9YcX8I.d.cts} +51 -17
  93. package/dist/index.cjs +14 -14
  94. package/dist/index.cjs.map +1 -1
  95. package/dist/index.d.cts +4 -2
  96. package/dist/index.d.ts +4 -2
  97. package/dist/index.js +13 -13
  98. package/dist/index.js.map +1 -1
  99. package/dist/testing.cjs +724 -0
  100. package/dist/testing.cjs.map +1 -1
  101. package/dist/testing.d.cts +14 -2
  102. package/dist/testing.d.ts +14 -2
  103. package/dist/testing.js +724 -0
  104. package/dist/testing.js.map +1 -1
  105. package/dist/{transport-Cdh3M0tS.d.cts → transport-DLWCN18G.d.cts} +1 -1
  106. package/dist/{transport-Ciap4PWK.d.ts → transport-DsuS-GeM.d.ts} +1 -1
  107. package/dist/{types-ajANVzf7.d.ts → types-DgtI1hzh.d.ts} +2 -1
  108. package/dist/{types-DRgd_9R7.d.cts → types-DkSXALKg.d.cts} +2 -1
  109. package/package.json +18 -7
  110. package/LICENSE +0 -21
  111. package/README.md +0 -1054
  112. package/dist/backends-BSrsBYFn.d.cts +0 -39
  113. package/dist/backends-BSrsBYFn.d.ts +0 -39
@@ -1,4 +1,5 @@
1
- import { existsSync, readdirSync, unlinkSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
1
+ import { existsSync, mkdirSync } from 'fs';
2
+ import { readdir, unlink, mkdir, access, readFile, writeFile } from 'fs/promises';
2
3
  import { join } from 'path';
3
4
 
4
5
  var __defProp = Object.defineProperty;
@@ -756,17 +757,6 @@ function convertParameters(params) {
756
757
  }
757
758
  return params;
758
759
  }
759
- async function mapToolsToSDKAsync(tools) {
760
- return tools.map((tool) => ({
761
- name: tool.name,
762
- description: tool.description,
763
- parameters: convertParameters(tool.parameters),
764
- handler: async (args) => {
765
- const result = await tool.execute(args);
766
- return typeof result === "string" ? result : JSON.stringify(result);
767
- }
768
- }));
769
- }
770
760
  function buildPermissionHandler(config) {
771
761
  const onPermission = config.supervisor?.onPermission;
772
762
  if (!onPermission) {
@@ -1004,15 +994,15 @@ var init_copilot = __esm({
1004
994
  },
1005
995
  onPermissionRequest: buildPermissionHandler(config),
1006
996
  onUserInputRequest: buildUserInputHandler(config),
1007
- ...config.availableTools?.length ? { availableTools: config.availableTools } : {}
997
+ ...config.availableTools ? { availableTools: config.availableTools } : {}
1008
998
  };
1009
999
  this._toolsReady = this._initToolsAsync(config);
1010
1000
  this._resumeSessionId = resumeSessionId;
1011
1001
  }
1012
- /** Pre-convert Zod schemas to JSON Schema asynchronously.
1002
+ /** Pre-convert Zod schemas to JSON Schema.
1013
1003
  * Updates sdkTools and sessionConfig.tools before first session creation. */
1014
1004
  async _initToolsAsync(config) {
1015
- this.sdkTools = await mapToolsToSDKAsync(config.tools ?? []);
1005
+ this.sdkTools = mapToolsToSDK(config.tools ?? []);
1016
1006
  this.sessionConfig.tools = this.sdkTools;
1017
1007
  }
1018
1008
  get sessionId() {
@@ -1303,7 +1293,11 @@ You MUST respond with ONLY valid JSON matching this schema:
1303
1293
  githubToken: this.options.githubToken,
1304
1294
  useLoggedInUser: this.options.useLoggedInUser ?? !this.options.githubToken,
1305
1295
  ...this.options.cliArgs ? { cliArgs: this.options.cliArgs } : {},
1306
- ...this.options.env ? { env: { ...process.env, ...this.options.env } } : {}
1296
+ env: {
1297
+ ...process.env,
1298
+ ...this.options.githubToken ? { GITHUB_TOKEN: this.options.githubToken } : {},
1299
+ ...this.options.env
1300
+ }
1307
1301
  });
1308
1302
  const startupTimeout = this.options.startupTimeoutMs ?? 3e4;
1309
1303
  await withTimeout(client.start(), startupTimeout, "CLI startup timed out");
@@ -2723,6 +2717,7 @@ var init_vercel_ai = __esm({
2723
2717
  }
2724
2718
  });
2725
2719
  let finalText = "";
2720
+ let lastFinishReason;
2726
2721
  try {
2727
2722
  for await (const part of result.fullStream) {
2728
2723
  if (signal.aborted) throw new AbortError();
@@ -2733,10 +2728,15 @@ var init_vercel_ai = __esm({
2733
2728
  }
2734
2729
  if (part.type === "finish-step") {
2735
2730
  const p = part;
2731
+ lastFinishReason = p.finishReason;
2736
2732
  if (p.finishReason === "tool-calls") {
2737
2733
  finalText = "";
2738
2734
  }
2739
2735
  }
2736
+ if (part.type === "finish") {
2737
+ const p = part;
2738
+ lastFinishReason = p.finishReason;
2739
+ }
2740
2740
  }
2741
2741
  const totalUsage = await result.totalUsage;
2742
2742
  yield {
@@ -2748,7 +2748,8 @@ var init_vercel_ai = __esm({
2748
2748
  yield {
2749
2749
  type: "done",
2750
2750
  finalOutput: hasStreamed ? null : finalText || null,
2751
- ...hasStreamed ? { streamed: true } : {}
2751
+ ...hasStreamed ? { streamed: true } : {},
2752
+ ...lastFinishReason ? { finishReason: lastFinishReason } : {}
2752
2753
  };
2753
2754
  } catch (e) {
2754
2755
  if (signal.aborted) throw new AbortError();
@@ -2910,30 +2911,30 @@ function isFilePart(value) {
2910
2911
  const obj = value;
2911
2912
  return obj.type === "file" && typeof obj.name === "string" && typeof obj.mimeType === "string";
2912
2913
  }
2914
+ var VALID_CHAT_EVENT_TYPES = /* @__PURE__ */ new Set([
2915
+ "message:start",
2916
+ "message:delta",
2917
+ "message:complete",
2918
+ "tool:start",
2919
+ "tool:complete",
2920
+ "thinking:start",
2921
+ "thinking:delta",
2922
+ "thinking:end",
2923
+ "permission:request",
2924
+ "permission:response",
2925
+ "usage",
2926
+ "session:created",
2927
+ "session:updated",
2928
+ "error",
2929
+ "typing:start",
2930
+ "typing:end",
2931
+ "heartbeat",
2932
+ "done"
2933
+ ]);
2913
2934
  function isChatEvent(value) {
2914
2935
  if (typeof value !== "object" || value === null) return false;
2915
2936
  const obj = value;
2916
- const validTypes = [
2917
- "message:start",
2918
- "message:delta",
2919
- "message:complete",
2920
- "tool:start",
2921
- "tool:complete",
2922
- "thinking:start",
2923
- "thinking:delta",
2924
- "thinking:end",
2925
- "permission:request",
2926
- "permission:response",
2927
- "usage",
2928
- "session:created",
2929
- "session:updated",
2930
- "error",
2931
- "typing:start",
2932
- "typing:end",
2933
- "heartbeat",
2934
- "done"
2935
- ];
2936
- return validTypes.includes(obj.type);
2937
+ return VALID_CHAT_EVENT_TYPES.has(obj.type);
2937
2938
  }
2938
2939
 
2939
2940
  // src/chat/bridge.ts
@@ -2997,8 +2998,9 @@ function agentEventToChatEvent(event, messageId) {
2997
2998
  case "ask_user":
2998
2999
  case "ask_user_response":
2999
3000
  case "session_info":
3000
- case "done":
3001
3001
  return null;
3002
+ case "done":
3003
+ return { type: "done", finalOutput: event.finalOutput ?? void 0, finishReason: event.finishReason };
3002
3004
  default:
3003
3005
  return null;
3004
3006
  }
@@ -3044,21 +3046,29 @@ function chatEventToAgentEvent(event) {
3044
3046
 
3045
3047
  // src/chat/conversion.ts
3046
3048
  function toAgentMessage(message) {
3049
+ return toAgentMessages(message)[0];
3050
+ }
3051
+ function toAgentMessages(message) {
3047
3052
  const textContent = getMessageText(message);
3048
3053
  const toolCallParts = getMessageToolCalls(message);
3049
3054
  switch (message.role) {
3050
3055
  case "user":
3051
- return { role: "user", content: textContent };
3056
+ return [{ role: "user", content: textContent }];
3052
3057
  case "assistant": {
3053
3058
  const toolCalls = toolCallParts.length > 0 ? toolCallParts.map((p) => ({ id: p.toolCallId, name: p.name, args: p.args })) : void 0;
3054
- return {
3059
+ const assistantMsg = {
3055
3060
  role: "assistant",
3056
3061
  content: textContent,
3057
3062
  toolCalls
3058
3063
  };
3064
+ const toolResults = extractToolResults(message);
3065
+ if (toolResults.length > 0) {
3066
+ return [assistantMsg, { role: "tool", toolResults }];
3067
+ }
3068
+ return [assistantMsg];
3059
3069
  }
3060
3070
  case "system":
3061
- return { role: "system", content: textContent };
3071
+ return [{ role: "system", content: textContent }];
3062
3072
  }
3063
3073
  }
3064
3074
  function fromAgentMessage(message, id) {
@@ -3104,6 +3114,14 @@ function fromAgentMessage(message, id) {
3104
3114
  status: "complete"
3105
3115
  };
3106
3116
  }
3117
+ function extractToolResults(message) {
3118
+ return getMessageToolCalls(message).filter((p) => p.result !== void 0).map((p) => ({
3119
+ toolCallId: p.toolCallId,
3120
+ name: p.name,
3121
+ result: p.result,
3122
+ isError: p.status === "error" ? true : void 0
3123
+ }));
3124
+ }
3107
3125
 
3108
3126
  // src/chat/context.ts
3109
3127
  function estimateTokens(message, options) {
@@ -3936,6 +3954,7 @@ var ChatRuntime = class {
3936
3954
  _backends;
3937
3955
  _sessionStore;
3938
3956
  _contextConfig;
3957
+ _ctxManager;
3939
3958
  _middleware;
3940
3959
  _tools = /* @__PURE__ */ new Map();
3941
3960
  _retryConfig;
@@ -3955,6 +3974,9 @@ var ChatRuntime = class {
3955
3974
  this._defaultBackend = options.defaultBackend;
3956
3975
  this._sessionStore = options.sessionStore;
3957
3976
  this._contextConfig = options.context;
3977
+ if (this._contextConfig) {
3978
+ this._ctxManager = new ContextWindowManager(this._contextConfig);
3979
+ }
3958
3980
  this._middleware = [...options.middleware ?? []];
3959
3981
  this._retryConfig = options.retryConfig;
3960
3982
  this._onContextTrimmed = options.onContextTrimmed;
@@ -4135,8 +4157,8 @@ var ChatRuntime = class {
4135
4157
  }
4136
4158
  /** Stage 5: Auto-trim context window if configured. Returns session snapshot for adapter. */
4137
4159
  async trimSessionContext(cid, session, model) {
4138
- if (!this._contextConfig) return session;
4139
- const ctxManager = new ContextWindowManager(this._contextConfig);
4160
+ if (!this._ctxManager) return session;
4161
+ const ctxManager = this._ctxManager;
4140
4162
  const lastUsage = this._sessionUsage.get(cid);
4141
4163
  const modelContextWindow = model ? this._modelContextWindows.get(model) : void 0;
4142
4164
  if (lastUsage && modelContextWindow) {
@@ -4552,25 +4574,25 @@ var FileStorage = class {
4552
4574
  constructor(options) {
4553
4575
  this.directory = options.directory;
4554
4576
  this.extension = options.extension ?? ".json";
4555
- this.ensureDirectory();
4577
+ this.ensureDirectorySync();
4556
4578
  }
4557
4579
  /** @inheritdoc */
4558
4580
  async get(key) {
4559
4581
  const filePath = this.keyToPath(key);
4560
- if (!existsSync(filePath)) {
4582
+ if (!await this.fileExists(filePath)) {
4561
4583
  return null;
4562
4584
  }
4563
- return this.readFile(filePath);
4585
+ return this.readJsonFile(filePath);
4564
4586
  }
4565
4587
  /** @inheritdoc */
4566
4588
  async list(options) {
4567
- this.ensureDirectory();
4568
- const files = readdirSync(this.directory).filter(
4589
+ await this.ensureDirectoryAsync();
4590
+ const files = (await readdir(this.directory)).filter(
4569
4591
  (f) => f.endsWith(this.extension)
4570
4592
  );
4571
4593
  let items = [];
4572
4594
  for (const file of files) {
4573
- const item = this.readFile(join(this.directory, file));
4595
+ const item = await this.readJsonFile(join(this.directory, file));
4574
4596
  items.push(item);
4575
4597
  }
4576
4598
  if (options?.filter) {
@@ -4590,55 +4612,55 @@ var FileStorage = class {
4590
4612
  /** @inheritdoc */
4591
4613
  async create(key, item) {
4592
4614
  const filePath = this.keyToPath(key);
4593
- if (existsSync(filePath)) {
4615
+ if (await this.fileExists(filePath)) {
4594
4616
  throw new StorageError(
4595
4617
  `Item with key "${key}" already exists`,
4596
4618
  "STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
4597
4619
  );
4598
4620
  }
4599
- this.writeFile(filePath, item);
4621
+ await this.writeJsonFile(filePath, item);
4600
4622
  }
4601
4623
  /** @inheritdoc */
4602
4624
  async update(key, item) {
4603
4625
  const filePath = this.keyToPath(key);
4604
- if (!existsSync(filePath)) {
4626
+ if (!await this.fileExists(filePath)) {
4605
4627
  throw new StorageError(
4606
4628
  `Item with key "${key}" not found`,
4607
4629
  "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
4608
4630
  );
4609
4631
  }
4610
- this.writeFile(filePath, item);
4632
+ await this.writeJsonFile(filePath, item);
4611
4633
  }
4612
4634
  /** @inheritdoc */
4613
4635
  async delete(key) {
4614
4636
  const filePath = this.keyToPath(key);
4615
- if (!existsSync(filePath)) {
4637
+ if (!await this.fileExists(filePath)) {
4616
4638
  throw new StorageError(
4617
4639
  `Item with key "${key}" not found`,
4618
4640
  "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
4619
4641
  );
4620
4642
  }
4621
- unlinkSync(filePath);
4643
+ await unlink(filePath);
4622
4644
  }
4623
4645
  /** @inheritdoc */
4624
4646
  async has(key) {
4625
- return existsSync(this.keyToPath(key));
4647
+ return this.fileExists(this.keyToPath(key));
4626
4648
  }
4627
4649
  /** @inheritdoc */
4628
4650
  async count() {
4629
- this.ensureDirectory();
4630
- return readdirSync(this.directory).filter(
4651
+ await this.ensureDirectoryAsync();
4652
+ return (await readdir(this.directory)).filter(
4631
4653
  (f) => f.endsWith(this.extension)
4632
4654
  ).length;
4633
4655
  }
4634
4656
  /** @inheritdoc */
4635
4657
  async clear() {
4636
- this.ensureDirectory();
4637
- const files = readdirSync(this.directory).filter(
4658
+ await this.ensureDirectoryAsync();
4659
+ const files = (await readdir(this.directory)).filter(
4638
4660
  (f) => f.endsWith(this.extension)
4639
4661
  );
4640
4662
  for (const file of files) {
4641
- unlinkSync(join(this.directory, file));
4663
+ await unlink(join(this.directory, file));
4642
4664
  }
4643
4665
  }
4644
4666
  keyToPath(key) {
@@ -4648,14 +4670,29 @@ var FileStorage = class {
4648
4670
  );
4649
4671
  return join(this.directory, `${safeKey}${this.extension}`);
4650
4672
  }
4651
- ensureDirectory() {
4673
+ /** Sync directory init — used only in constructor (one-time). */
4674
+ ensureDirectorySync() {
4652
4675
  if (!existsSync(this.directory)) {
4653
4676
  mkdirSync(this.directory, { recursive: true });
4654
4677
  }
4655
4678
  }
4656
- readFile(filePath) {
4679
+ /** Async directory init — used in operations. */
4680
+ async ensureDirectoryAsync() {
4681
+ if (!await this.fileExists(this.directory)) {
4682
+ await mkdir(this.directory, { recursive: true });
4683
+ }
4684
+ }
4685
+ async fileExists(filePath) {
4686
+ try {
4687
+ await access(filePath);
4688
+ return true;
4689
+ } catch {
4690
+ return false;
4691
+ }
4692
+ }
4693
+ async readJsonFile(filePath) {
4657
4694
  try {
4658
- const content = readFileSync(filePath, "utf-8");
4695
+ const content = await readFile(filePath, "utf-8");
4659
4696
  return JSON.parse(content);
4660
4697
  } catch (error) {
4661
4698
  if (error instanceof SyntaxError) {
@@ -4670,10 +4707,10 @@ var FileStorage = class {
4670
4707
  );
4671
4708
  }
4672
4709
  }
4673
- writeFile(filePath, item) {
4710
+ async writeJsonFile(filePath, item) {
4674
4711
  try {
4675
4712
  const content = JSON.stringify(item, null, 2);
4676
- writeFileSync(filePath, content, "utf-8");
4713
+ await writeFile(filePath, content, "utf-8");
4677
4714
  } catch {
4678
4715
  throw new StorageError(
4679
4716
  `Failed to write file: ${filePath}`,
@@ -4892,7 +4929,7 @@ var BaseBackendAdapter = class {
4892
4929
  async *streamMessage(session, message, options) {
4893
4930
  this.assertNotDisposed();
4894
4931
  const agent = this.getOrCreateAgent(options);
4895
- const messages = session.messages.map(toAgentMessage);
4932
+ const messages = session.messages.flatMap(toAgentMessages);
4896
4933
  messages.push({ role: "user", content: message });
4897
4934
  yield* this.streamAgentEvents(agent, messages, options);
4898
4935
  }
@@ -4969,7 +5006,8 @@ var BaseBackendAdapter = class {
4969
5006
  }
4970
5007
  const config = {
4971
5008
  ...this._agentConfig,
4972
- ...model !== void 0 && { model }
5009
+ ...model !== void 0 && { model },
5010
+ ...options?.tools?.length ? { tools: options.tools } : {}
4973
5011
  };
4974
5012
  const agent = this.agentService.createAgent(config);
4975
5013
  this._currentAgent = { instance: agent, model };
@@ -4984,21 +5022,15 @@ var BaseBackendAdapter = class {
4984
5022
  }
4985
5023
  };
4986
5024
 
4987
- // src/chat/backends/copilot.ts
4988
- var CopilotChatAdapter = class extends BaseBackendAdapter {
5025
+ // src/chat/backends/resumable.ts
5026
+ var ResumableChatAdapter = class extends BaseBackendAdapter {
4989
5027
  _backendSessionId = null;
4990
- _copilotOptions;
4991
- constructor(options) {
5028
+ constructor(name, options) {
4992
5029
  const agentConfig = {
4993
5030
  ...options.agentConfig,
4994
5031
  sessionMode: "persistent"
4995
5032
  };
4996
- super("copilot", { ...options, agentConfig });
4997
- this._copilotOptions = options.copilotOptions;
4998
- }
4999
- createService() {
5000
- const { createCopilotService: createCopilotService2 } = (init_copilot(), __toCommonJS(copilot_exports));
5001
- return createCopilotService2(this._copilotOptions || {});
5033
+ super(name, { ...options, agentConfig });
5002
5034
  }
5003
5035
  get backendSessionId() {
5004
5036
  return this._backendSessionId;
@@ -5027,7 +5059,7 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
5027
5059
  { code: "SESSION_EXPIRED" /* SESSION_EXPIRED */ }
5028
5060
  );
5029
5061
  }
5030
- const messages = session.messages.map(toAgentMessage);
5062
+ const messages = session.messages.flatMap(toAgentMessages);
5031
5063
  yield* this.streamAgentEvents(agent, messages, options);
5032
5064
  }
5033
5065
  captureSessionId(agent) {
@@ -5037,69 +5069,325 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
5037
5069
  }
5038
5070
  };
5039
5071
 
5072
+ // src/chat/backends/copilot.ts
5073
+ var CopilotChatAdapter = class extends ResumableChatAdapter {
5074
+ _copilotOptions;
5075
+ constructor(options) {
5076
+ super("copilot", options);
5077
+ this._copilotOptions = options.copilotOptions;
5078
+ }
5079
+ createService() {
5080
+ const { createCopilotService: createCopilotService2 } = (init_copilot(), __toCommonJS(copilot_exports));
5081
+ return createCopilotService2(this._copilotOptions || {});
5082
+ }
5083
+ };
5084
+
5040
5085
  // src/chat/backends/claude.ts
5041
- var ClaudeChatAdapter = class extends BaseBackendAdapter {
5042
- _backendSessionId = null;
5086
+ var ClaudeChatAdapter = class extends ResumableChatAdapter {
5043
5087
  _claudeOptions;
5044
5088
  constructor(options) {
5045
- const agentConfig = {
5046
- ...options.agentConfig,
5047
- sessionMode: "persistent"
5048
- };
5049
- super("claude", { ...options, agentConfig });
5089
+ super("claude", options);
5050
5090
  this._claudeOptions = options.claudeOptions;
5051
5091
  }
5052
5092
  createService() {
5053
5093
  const { createClaudeService: createClaudeService2 } = (init_claude(), __toCommonJS(claude_exports));
5054
5094
  return createClaudeService2(this._claudeOptions || {});
5055
5095
  }
5056
- get backendSessionId() {
5057
- return this._backendSessionId;
5096
+ };
5097
+
5098
+ // src/chat/backends/vercel-ai.ts
5099
+ var VercelAIChatAdapter = class extends BaseBackendAdapter {
5100
+ _vercelOptions;
5101
+ constructor(options) {
5102
+ super("vercel-ai", options);
5103
+ this._vercelOptions = options.vercelOptions;
5058
5104
  }
5059
- canResume() {
5060
- return this._backendSessionId !== null;
5105
+ createService() {
5106
+ const { createVercelAIService: createVercelAIService2 } = (init_vercel_ai(), __toCommonJS(vercel_ai_exports));
5107
+ return createVercelAIService2(this._vercelOptions || {});
5061
5108
  }
5062
- async *resume(session, backendSessionId, options) {
5063
- this.assertNotDisposed();
5064
- if (!backendSessionId) {
5065
- throw new ChatError("Backend session ID is required for resume", {
5066
- code: "INVALID_INPUT" /* INVALID_INPUT */
5109
+ captureSessionId(_agent) {
5110
+ }
5111
+ };
5112
+
5113
+ // src/backends/mock-llm.ts
5114
+ init_base_agent();
5115
+ init_errors2();
5116
+ function extractPrompt(messages) {
5117
+ for (let i = messages.length - 1; i >= 0; i--) {
5118
+ const msg = messages[i];
5119
+ if (msg.role === "user") {
5120
+ return typeof msg.content === "string" ? msg.content : msg.content.filter((p) => p.type === "text").map((p) => p.text).join("");
5121
+ }
5122
+ }
5123
+ return "";
5124
+ }
5125
+ function resolveResponse(mode, messages, callIndex) {
5126
+ switch (mode.type) {
5127
+ case "echo":
5128
+ return extractPrompt(messages);
5129
+ case "static":
5130
+ return mode.response;
5131
+ case "scripted": {
5132
+ if (mode.loop) {
5133
+ return mode.responses[callIndex % mode.responses.length];
5134
+ }
5135
+ if (callIndex < mode.responses.length) {
5136
+ return mode.responses[callIndex];
5137
+ }
5138
+ return mode.responses[mode.responses.length - 1];
5139
+ }
5140
+ case "error":
5141
+ throw new AgentSDKError(mode.error, {
5142
+ code: mode.code ?? "backend_error",
5143
+ retryable: mode.recoverable ?? false
5067
5144
  });
5145
+ }
5146
+ }
5147
+ async function applyLatency(latency, signal) {
5148
+ if (!latency) return;
5149
+ const ms = latency.type === "fixed" ? latency.ms : latency.minMs + Math.random() * (latency.maxMs - latency.minMs);
5150
+ if (ms <= 0) return;
5151
+ await new Promise((resolve, reject) => {
5152
+ const timer = setTimeout(resolve, ms);
5153
+ const onAbort = () => {
5154
+ clearTimeout(timer);
5155
+ reject(new Error("aborted"));
5156
+ };
5157
+ if (signal.aborted) {
5158
+ clearTimeout(timer);
5159
+ reject(new Error("aborted"));
5160
+ return;
5068
5161
  }
5069
- const agent = this.getOrCreateAgent(options);
5070
- const currentSessionId = agent.sessionId;
5071
- if (!currentSessionId) {
5072
- throw new ChatError(
5073
- `No active session to resume (requested: ${backendSessionId})`,
5074
- { code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
5075
- );
5162
+ signal.addEventListener("abort", onAbort, { once: true });
5163
+ });
5164
+ }
5165
+ function chunkText(text, streaming) {
5166
+ if (streaming?.chunkSize && streaming.chunkSize > 0) {
5167
+ const chunks = [];
5168
+ for (let i = 0; i < text.length; i += streaming.chunkSize) {
5169
+ chunks.push(text.slice(i, i + streaming.chunkSize));
5076
5170
  }
5077
- if (currentSessionId !== backendSessionId) {
5078
- throw new ChatError(
5079
- `Session expired: expected ${backendSessionId}, got ${currentSessionId}`,
5080
- { code: "SESSION_EXPIRED" /* SESSION_EXPIRED */ }
5081
- );
5171
+ return chunks;
5172
+ }
5173
+ return text.split(/(\s+)/).filter(Boolean);
5174
+ }
5175
+ async function chunkDelay(streaming, signal) {
5176
+ const ms = streaming?.chunkDelayMs;
5177
+ if (!ms || ms <= 0) return;
5178
+ await new Promise((resolve, reject) => {
5179
+ const timer = setTimeout(resolve, ms);
5180
+ const onAbort = () => {
5181
+ clearTimeout(timer);
5182
+ reject(new Error("aborted"));
5183
+ };
5184
+ if (signal.aborted) {
5185
+ clearTimeout(timer);
5186
+ reject(new Error("aborted"));
5187
+ return;
5082
5188
  }
5083
- const messages = session.messages.map(toAgentMessage);
5084
- yield* this.streamAgentEvents(agent, messages, options);
5189
+ signal.addEventListener("abort", onAbort, { once: true });
5190
+ });
5191
+ }
5192
+ var MockLLMAgent = class extends BaseAgent {
5193
+ backendName = "mock-llm";
5194
+ mode;
5195
+ latency;
5196
+ streaming;
5197
+ finishReason;
5198
+ permissions;
5199
+ toolCallConfigs;
5200
+ configuredStructuredOutput;
5201
+ callIndex = 0;
5202
+ constructor(config, options) {
5203
+ super(config);
5204
+ this.mode = options.mode ?? { type: "echo" };
5205
+ this.latency = options.latency;
5206
+ this.streaming = options.streaming;
5207
+ this.finishReason = options.finishReason ?? "stop";
5208
+ this.permissions = options.permissions;
5209
+ this.toolCallConfigs = options.toolCalls ?? [];
5210
+ this.configuredStructuredOutput = options.structuredOutput;
5211
+ }
5212
+ async executeRun(messages, _options, signal) {
5213
+ this.checkAbort(signal);
5214
+ await applyLatency(this.latency, signal);
5215
+ this.checkAbort(signal);
5216
+ const idx = this.callIndex++;
5217
+ const output = resolveResponse(this.mode, messages, idx);
5218
+ const toolCalls = this.toolCallConfigs.map((tc) => ({
5219
+ toolName: tc.toolName,
5220
+ args: tc.args ?? {},
5221
+ result: tc.result ?? null,
5222
+ approved: true
5223
+ }));
5224
+ return {
5225
+ output,
5226
+ structuredOutput: void 0,
5227
+ toolCalls,
5228
+ messages: [
5229
+ ...messages,
5230
+ { role: "assistant", content: output }
5231
+ ],
5232
+ usage: { promptTokens: 10, completionTokens: output.length }
5233
+ };
5085
5234
  }
5086
- captureSessionId(agent) {
5087
- if (agent.sessionId) {
5088
- this._backendSessionId = agent.sessionId;
5235
+ async executeRunStructured(messages, _schema, _options, signal) {
5236
+ this.checkAbort(signal);
5237
+ await applyLatency(this.latency, signal);
5238
+ this.checkAbort(signal);
5239
+ const idx = this.callIndex++;
5240
+ const output = resolveResponse(this.mode, messages, idx);
5241
+ let parsed;
5242
+ if (this.configuredStructuredOutput !== void 0) {
5243
+ parsed = this.configuredStructuredOutput;
5244
+ } else {
5245
+ try {
5246
+ parsed = JSON.parse(output);
5247
+ } catch {
5248
+ parsed = output;
5249
+ }
5089
5250
  }
5251
+ return {
5252
+ output,
5253
+ structuredOutput: parsed,
5254
+ toolCalls: [],
5255
+ messages: [
5256
+ ...messages,
5257
+ { role: "assistant", content: output }
5258
+ ],
5259
+ usage: { promptTokens: 10, completionTokens: output.length }
5260
+ };
5261
+ }
5262
+ async *executeStream(messages, _options, signal) {
5263
+ this.checkAbort(signal);
5264
+ await applyLatency(this.latency, signal);
5265
+ this.checkAbort(signal);
5266
+ if (this.permissions) {
5267
+ yield* this.simulatePermissions(signal);
5268
+ }
5269
+ if (this.toolCallConfigs.length > 0) {
5270
+ yield* this.simulateToolCalls(signal);
5271
+ }
5272
+ const idx = this.callIndex++;
5273
+ const output = resolveResponse(this.mode, messages, idx);
5274
+ const chunks = chunkText(output, this.streaming);
5275
+ for (let i = 0; i < chunks.length; i++) {
5276
+ this.checkAbort(signal);
5277
+ if (i > 0) {
5278
+ await chunkDelay(this.streaming, signal);
5279
+ }
5280
+ yield { type: "text_delta", text: chunks[i] };
5281
+ }
5282
+ yield {
5283
+ type: "usage_update",
5284
+ promptTokens: 10,
5285
+ completionTokens: output.length
5286
+ };
5287
+ yield {
5288
+ type: "done",
5289
+ finalOutput: output,
5290
+ finishReason: this.finishReason
5291
+ };
5292
+ }
5293
+ async *simulateToolCalls(signal) {
5294
+ for (let i = 0; i < this.toolCallConfigs.length; i++) {
5295
+ this.checkAbort(signal);
5296
+ const tc = this.toolCallConfigs[i];
5297
+ const toolCallId = tc.toolCallId ?? `mock-tc-${i}`;
5298
+ yield {
5299
+ type: "tool_call_start",
5300
+ toolCallId,
5301
+ toolName: tc.toolName,
5302
+ args: tc.args ?? {}
5303
+ };
5304
+ yield {
5305
+ type: "tool_call_end",
5306
+ toolCallId,
5307
+ toolName: tc.toolName,
5308
+ result: tc.result ?? null
5309
+ };
5310
+ }
5311
+ }
5312
+ async *simulatePermissions(signal) {
5313
+ const perms = this.permissions;
5314
+ for (const toolName of perms.toolNames) {
5315
+ this.checkAbort(signal);
5316
+ const request = {
5317
+ toolName,
5318
+ toolArgs: {}
5319
+ };
5320
+ yield { type: "permission_request", request };
5321
+ if (perms.denyTools?.includes(toolName)) {
5322
+ yield {
5323
+ type: "permission_response",
5324
+ toolName,
5325
+ decision: { allowed: false, reason: "Denied by mock configuration" }
5326
+ };
5327
+ } else if (perms.autoApprove) {
5328
+ yield {
5329
+ type: "permission_response",
5330
+ toolName,
5331
+ decision: { allowed: true, scope: "once" }
5332
+ };
5333
+ } else {
5334
+ const supervisor = this.getConfig().supervisor;
5335
+ if (supervisor?.onPermission) {
5336
+ const decision = await supervisor.onPermission(request, signal);
5337
+ yield { type: "permission_response", toolName, decision };
5338
+ } else {
5339
+ yield {
5340
+ type: "permission_response",
5341
+ toolName,
5342
+ decision: { allowed: true, scope: "once" }
5343
+ };
5344
+ }
5345
+ }
5346
+ }
5347
+ }
5348
+ };
5349
+ var MockLLMService = class {
5350
+ name = "mock-llm";
5351
+ options;
5352
+ models;
5353
+ constructor(options = {}) {
5354
+ this.options = options;
5355
+ this.models = (options.models ?? [
5356
+ { id: "mock-fast", name: "Mock Fast" },
5357
+ { id: "mock-quality", name: "Mock Quality" }
5358
+ ]).map((m) => ({
5359
+ id: m.id,
5360
+ name: m.name,
5361
+ description: m.description
5362
+ }));
5363
+ }
5364
+ createAgent(config) {
5365
+ return new MockLLMAgent(config, this.options);
5366
+ }
5367
+ async listModels() {
5368
+ return this.models;
5369
+ }
5370
+ async validate() {
5371
+ return { valid: true, errors: [] };
5372
+ }
5373
+ async dispose() {
5090
5374
  }
5091
5375
  };
5376
+ function createMockLLMService(options = {}) {
5377
+ return new MockLLMService(options);
5378
+ }
5092
5379
 
5093
- // src/chat/backends/vercel-ai.ts
5094
- var VercelAIChatAdapter = class extends BaseBackendAdapter {
5095
- _vercelOptions;
5380
+ // src/chat/backends/mock-llm.ts
5381
+ var MockLLMChatAdapter = class extends BaseBackendAdapter {
5096
5382
  constructor(options) {
5097
- super("vercel-ai", options);
5098
- this._vercelOptions = options.vercelOptions;
5383
+ const mockOpts = options.mockOptions;
5384
+ super("mock-llm", {
5385
+ ...options,
5386
+ agentServiceFactory: () => createMockLLMService(mockOpts || {})
5387
+ });
5099
5388
  }
5100
5389
  createService() {
5101
- const { createVercelAIService: createVercelAIService2 } = (init_vercel_ai(), __toCommonJS(vercel_ai_exports));
5102
- return createVercelAIService2(this._vercelOptions || {});
5390
+ return createMockLLMService({});
5103
5391
  }
5104
5392
  captureSessionId(_agent) {
5105
5393
  }
@@ -5180,16 +5468,22 @@ var SSEChatTransport = class {
5180
5468
  };
5181
5469
  async function streamToTransport(events, transport) {
5182
5470
  try {
5183
- let accumulatedText = "";
5471
+ const textChunks = [];
5472
+ let finishReason;
5184
5473
  for await (const event of events) {
5185
5474
  if (!transport.isOpen) break;
5475
+ if (event.type === "done") {
5476
+ finishReason = event.finishReason;
5477
+ continue;
5478
+ }
5186
5479
  transport.send(event);
5187
5480
  if (event.type === "message:delta") {
5188
- accumulatedText += event.text;
5481
+ textChunks.push(event.text);
5189
5482
  }
5190
5483
  }
5191
5484
  if (transport.isOpen) {
5192
- transport.send({ type: "done", finalOutput: accumulatedText || void 0 });
5485
+ const finalOutput = textChunks.length > 0 ? textChunks.join("") : void 0;
5486
+ transport.send({ type: "done", finalOutput, finishReason });
5193
5487
  }
5194
5488
  transport.close();
5195
5489
  } catch (err) {
@@ -5500,6 +5794,6 @@ var ChatEventBus = class extends TypedEventEmitter {
5500
5794
  }
5501
5795
  };
5502
5796
 
5503
- export { BaseBackendAdapter, ChatError, ChatEventBus, ClaudeChatAdapter, ContextWindowManager, CopilotChatAdapter, ErrorCode, ExponentialBackoffStrategy, FileSessionStore, InMemorySessionStore, InProcessChatTransport, ListenerSet, MessageAccumulator, SSEChatTransport, TypedEventEmitter, VercelAIChatAdapter, WsChatTransport, adaptAgentEvents, agentEventToChatEvent, classifyError, createChatId, createChatRuntime, createTextMessage, estimateTokens, fromAgentMessage, getMessageReasoning, getMessageText, getMessageToolCalls, isChatEvent, isChatMessage, isChatSession, isFilePart, isMessagePart, isObservableSession, isReasoningPart, isResumableBackend, isRetryable, isSourcePart, isTextPart, isToolCallPart, streamToTransport, toAgentMessage, toChatId, withRetry, withStreamWatchdog };
5797
+ export { BaseBackendAdapter, ChatError, ChatEventBus, ClaudeChatAdapter, ContextWindowManager, CopilotChatAdapter, ErrorCode, ExponentialBackoffStrategy, FileSessionStore, InMemorySessionStore, InProcessChatTransport, ListenerSet, MessageAccumulator, MockLLMChatAdapter, SSEChatTransport, TypedEventEmitter, VercelAIChatAdapter, WsChatTransport, adaptAgentEvents, agentEventToChatEvent, classifyError, createChatId, createChatRuntime, createTextMessage, estimateTokens, fromAgentMessage, getMessageReasoning, getMessageText, getMessageToolCalls, isChatEvent, isChatMessage, isChatSession, isFilePart, isMessagePart, isObservableSession, isReasoningPart, isResumableBackend, isRetryable, isSourcePart, isTextPart, isToolCallPart, streamToTransport, toAgentMessage, toAgentMessages, toChatId, withRetry, withStreamWatchdog };
5504
5798
  //# sourceMappingURL=index.js.map
5505
5799
  //# sourceMappingURL=index.js.map