@witqq/agent-sdk 0.3.1 → 0.5.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.
@@ -41,6 +41,10 @@ var BaseAgent = class {
41
41
  state = "idle";
42
42
  abortController = null;
43
43
  config;
44
+ /** CLI session ID for persistent mode. Override in backends that support it. */
45
+ get sessionId() {
46
+ return void 0;
47
+ }
44
48
  constructor(config) {
45
49
  this.config = Object.freeze({ ...config });
46
50
  }
@@ -126,6 +130,10 @@ var BaseAgent = class {
126
130
  this.abortController.abort();
127
131
  }
128
132
  }
133
+ /** Default interrupt — falls back to abort(). Backends may override with graceful shutdown. */
134
+ async interrupt() {
135
+ this.abort();
136
+ }
129
137
  getState() {
130
138
  return this.state;
131
139
  }
@@ -335,12 +343,9 @@ function _injectSDK(mock) {
335
343
  function _resetSDK() {
336
344
  sdkModule = null;
337
345
  }
338
- var CLAUDE_KNOWN_MODELS = [
339
- { id: "claude-sonnet-4-5-20250514", name: "Claude Sonnet 4.5" },
340
- { id: "claude-haiku-3-5-20241022", name: "Claude 3.5 Haiku" },
341
- { id: "claude-opus-4-20250514", name: "Claude Opus 4" },
342
- { id: "claude-sonnet-4-20250514", name: "Claude Sonnet 4" }
343
- ];
346
+ var ANTHROPIC_MODELS_URL = "https://api.anthropic.com/v1/models";
347
+ var ANTHROPIC_API_VERSION = "2023-06-01";
348
+ var ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
344
349
  function buildMcpServer(sdk, tools, toolResultCapture) {
345
350
  if (tools.length === 0) return void 0;
346
351
  const mcpTools = tools.map(
@@ -584,17 +589,43 @@ var ClaudeAgent = class extends BaseAgent {
584
589
  options;
585
590
  tools;
586
591
  canUseTool;
592
+ isPersistent;
593
+ _sessionId;
594
+ activeQuery = null;
587
595
  constructor(config, options) {
588
596
  super(config);
589
597
  this.options = options;
590
598
  this.tools = config.tools;
591
599
  this.canUseTool = buildCanUseTool(config);
600
+ this.isPersistent = config.sessionMode === "persistent";
592
601
  if (config.supervisor?.onAskUser) {
593
602
  console.warn(
594
603
  "[agent-sdk/claude] supervisor.onAskUser is not supported by the Claude CLI backend. User interaction requests from the model will not be forwarded."
595
604
  );
596
605
  }
597
606
  }
607
+ get sessionId() {
608
+ return this._sessionId;
609
+ }
610
+ async interrupt() {
611
+ try {
612
+ if (this.activeQuery) {
613
+ await this.activeQuery.interrupt();
614
+ }
615
+ } catch {
616
+ } finally {
617
+ this.abort();
618
+ }
619
+ }
620
+ /** Clear persistent session state after an error so next call starts fresh */
621
+ clearPersistentSession() {
622
+ this._sessionId = void 0;
623
+ }
624
+ emitSessionInfo(sessionId) {
625
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
626
+ const transcriptPath = home ? `${home}/.claude/projects/.session/sessions/${sessionId}/conversation.jsonl` : void 0;
627
+ return { type: "session_info", sessionId, transcriptPath, backend: "claude" };
628
+ }
598
629
  buildQueryOptions(signal) {
599
630
  const ac = new AbortController();
600
631
  signal.addEventListener("abort", () => ac.abort(), { once: true });
@@ -604,13 +635,26 @@ var ClaudeAgent = class extends BaseAgent {
604
635
  maxTurns: this.options.maxTurns,
605
636
  cwd: this.options.workingDirectory,
606
637
  pathToClaudeCodeExecutable: this.options.cliPath,
607
- persistSession: false,
638
+ persistSession: this.isPersistent,
608
639
  includePartialMessages: true,
609
640
  canUseTool: this.canUseTool
610
641
  };
642
+ if (this.isPersistent && this._sessionId) {
643
+ opts.resume = this._sessionId;
644
+ }
611
645
  if (this.config.systemPrompt) {
612
646
  opts.systemPrompt = this.config.systemPrompt;
613
647
  }
648
+ if (this.options.oauthToken || this.options.env) {
649
+ opts.env = {
650
+ ...process.env,
651
+ ...this.options.env ?? {},
652
+ ...this.options.oauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: this.options.oauthToken } : {}
653
+ };
654
+ }
655
+ if (opts.canUseTool && !opts.permissionMode) {
656
+ opts.permissionMode = "default";
657
+ }
614
658
  return opts;
615
659
  }
616
660
  async buildMcpConfig(opts, toolResultCapture) {
@@ -628,11 +672,13 @@ var ClaudeAgent = class extends BaseAgent {
628
672
  async executeRun(messages, _options, signal) {
629
673
  this.checkAbort(signal);
630
674
  const sdk = await loadSDK();
631
- const prompt = extractLastUserPrompt(messages);
675
+ const isResuming = this.isPersistent && this._sessionId !== void 0;
676
+ const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
632
677
  let opts = this.buildQueryOptions(signal);
633
678
  const toolResultCapture = /* @__PURE__ */ new Map();
634
679
  opts = await this.buildMcpConfig(opts, toolResultCapture);
635
680
  const q = sdk.query({ prompt, options: opts });
681
+ this.activeQuery = q;
636
682
  const toolCalls = [];
637
683
  let output = null;
638
684
  let usage;
@@ -667,6 +713,9 @@ var ClaudeAgent = class extends BaseAgent {
667
713
  const r = msg;
668
714
  output = r.result;
669
715
  usage = aggregateUsage(r.modelUsage);
716
+ if (this.isPersistent && r.session_id) {
717
+ this._sessionId = r.session_id;
718
+ }
670
719
  } else if (msg.is_error) {
671
720
  const r = msg;
672
721
  throw new Error(
@@ -676,8 +725,11 @@ var ClaudeAgent = class extends BaseAgent {
676
725
  }
677
726
  }
678
727
  } catch (e) {
728
+ if (this.isPersistent) this.clearPersistentSession();
679
729
  if (signal.aborted) throw new AbortError();
680
730
  throw e;
731
+ } finally {
732
+ this.activeQuery = null;
681
733
  }
682
734
  return {
683
735
  output,
@@ -694,7 +746,8 @@ var ClaudeAgent = class extends BaseAgent {
694
746
  async executeRunStructured(messages, schema, _options, signal) {
695
747
  this.checkAbort(signal);
696
748
  const sdk = await loadSDK();
697
- const prompt = extractLastUserPrompt(messages);
749
+ const isResuming = this.isPersistent && this._sessionId !== void 0;
750
+ const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
698
751
  let opts = this.buildQueryOptions(signal);
699
752
  opts = await this.buildMcpConfig(opts);
700
753
  const jsonSchema = zodToJsonSchema(schema.schema);
@@ -703,6 +756,7 @@ var ClaudeAgent = class extends BaseAgent {
703
756
  schema: jsonSchema
704
757
  };
705
758
  const q = sdk.query({ prompt, options: opts });
759
+ this.activeQuery = q;
706
760
  const toolCalls = [];
707
761
  let output = null;
708
762
  let structuredOutput;
@@ -730,6 +784,9 @@ var ClaudeAgent = class extends BaseAgent {
730
784
  }
731
785
  }
732
786
  usage = aggregateUsage(r.modelUsage);
787
+ if (this.isPersistent && r.session_id) {
788
+ this._sessionId = r.session_id;
789
+ }
733
790
  } else if (msg.type === "result" && msg.is_error) {
734
791
  const r = msg;
735
792
  throw new Error(
@@ -738,8 +795,11 @@ var ClaudeAgent = class extends BaseAgent {
738
795
  }
739
796
  }
740
797
  } catch (e) {
798
+ if (this.isPersistent) this.clearPersistentSession();
741
799
  if (signal.aborted) throw new AbortError();
742
800
  throw e;
801
+ } finally {
802
+ this.activeQuery = null;
743
803
  }
744
804
  return {
745
805
  output,
@@ -756,10 +816,12 @@ var ClaudeAgent = class extends BaseAgent {
756
816
  async *executeStream(messages, _options, signal) {
757
817
  this.checkAbort(signal);
758
818
  const sdk = await loadSDK();
759
- const prompt = extractLastUserPrompt(messages);
819
+ const isResuming = this.isPersistent && this._sessionId !== void 0;
820
+ const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
760
821
  let opts = this.buildQueryOptions(signal);
761
822
  opts = await this.buildMcpConfig(opts);
762
823
  const q = sdk.query({ prompt, options: opts });
824
+ this.activeQuery = q;
763
825
  const thinkingBlockIndices = /* @__PURE__ */ new Set();
764
826
  const toolCallTracker = new ClaudeToolCallTracker();
765
827
  try {
@@ -775,15 +837,25 @@ var ClaudeAgent = class extends BaseAgent {
775
837
  }
776
838
  if (msg.type === "result" && msg.subtype === "success") {
777
839
  const r = msg;
840
+ if (r.session_id) {
841
+ if (this.isPersistent) {
842
+ this._sessionId = r.session_id;
843
+ }
844
+ yield this.emitSessionInfo(r.session_id);
845
+ }
778
846
  yield { type: "done", finalOutput: r.result };
779
847
  }
780
848
  }
781
849
  } catch (e) {
850
+ if (this.isPersistent) this.clearPersistentSession();
782
851
  if (signal.aborted) throw new AbortError();
783
852
  throw e;
853
+ } finally {
854
+ this.activeQuery = null;
784
855
  }
785
856
  }
786
857
  dispose() {
858
+ this._sessionId = void 0;
787
859
  super.dispose();
788
860
  }
789
861
  };
@@ -796,6 +868,20 @@ function extractLastUserPrompt(messages) {
796
868
  }
797
869
  return "";
798
870
  }
871
+ function buildContextualPrompt(messages) {
872
+ if (messages.length <= 1) {
873
+ return extractLastUserPrompt(messages);
874
+ }
875
+ const history = messages.slice(0, -1).map((msg) => {
876
+ const text = msg.content ? getTextContent(msg.content) : "";
877
+ return msg.role === "user" ? `User: ${text}` : `Assistant: ${text}`;
878
+ }).join("\n");
879
+ const lastPrompt = extractLastUserPrompt(messages);
880
+ return `Conversation history:
881
+ ${history}
882
+
883
+ User: ${lastPrompt}`;
884
+ }
799
885
  var ClaudeAgentService = class {
800
886
  name = "claude";
801
887
  disposed = false;
@@ -811,9 +897,30 @@ var ClaudeAgentService = class {
811
897
  async listModels() {
812
898
  if (this.disposed) throw new DisposedError("ClaudeAgentService");
813
899
  if (this.cachedModels) return this.cachedModels;
814
- this.cachedModels = CLAUDE_KNOWN_MODELS.map((m) => ({
900
+ const token = this.options.oauthToken;
901
+ if (!token) {
902
+ return [];
903
+ }
904
+ const res = await globalThis.fetch(
905
+ `${ANTHROPIC_MODELS_URL}?limit=100`,
906
+ {
907
+ headers: {
908
+ Authorization: `Bearer ${token}`,
909
+ "anthropic-version": ANTHROPIC_API_VERSION,
910
+ "anthropic-beta": ANTHROPIC_OAUTH_BETA
911
+ }
912
+ }
913
+ );
914
+ if (!res.ok) {
915
+ return [];
916
+ }
917
+ const body = await res.json();
918
+ if (!body.data || body.data.length === 0) {
919
+ return [];
920
+ }
921
+ this.cachedModels = body.data.map((m) => ({
815
922
  id: m.id,
816
- name: m.name,
923
+ name: m.display_name,
817
924
  provider: "claude"
818
925
  }));
819
926
  return this.cachedModels;
@@ -834,7 +941,7 @@ var ClaudeAgentService = class {
834
941
  const q = sdk.query({
835
942
  prompt: "echo test",
836
943
  options: {
837
- model: CLAUDE_KNOWN_MODELS[0].id,
944
+ model: "claude-sonnet-4-20250514",
838
945
  pathToClaudeCodeExecutable: this.options.cliPath,
839
946
  cwd: this.options.workingDirectory,
840
947
  persistSession: false,