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