@witqq/agent-sdk 0.4.0 → 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.
package/README.md CHANGED
@@ -225,6 +225,7 @@ for await (const event of agent.streamWithContext(messages)) {
225
225
  | `permission_response` | `toolName`, `decision` | Permission decision made |
226
226
  | `ask_user` | `request` | User input requested |
227
227
  | `ask_user_response` | `answer` | User response received |
228
+ | `session_info` | `sessionId`, `transcriptPath?`, `backend` | CLI session metadata (streaming only) |
228
229
  | `usage_update` | `promptTokens`, `completionTokens`, `model?`, `backend?` | Token usage with metadata |
229
230
  | `heartbeat` | — | Keepalive signal during long operations |
230
231
  | `error` | `error`, `recoverable` | Error during execution |
@@ -283,6 +284,15 @@ agent.dispose(); // destroys the persistent session
283
284
 
284
285
  In persistent mode, if a session encounters an error, it is automatically cleared and recreated on the next call. The `sessionId` property exposes the CLI session ID for logging or external storage.
285
286
 
287
+ ### Interrupting Running Operations
288
+
289
+ Call `interrupt()` to gracefully stop a running operation. For CLI backends, this calls the SDK's interrupt/abort method on the active session:
290
+
291
+ ```typescript
292
+ // In another context (e.g., timeout handler)
293
+ await agent.interrupt();
294
+ ```
295
+
286
296
  Default (`"per-call"`): each call creates and destroys a fresh session. Multi-message context is passed via prompt augmentation through `runWithContext()`/`streamWithContext()`.
287
297
 
288
298
  API-based backends (Vercel AI) ignore `sessionMode` — they are stateless by design.
@@ -300,6 +310,7 @@ const service = createCopilotService({
300
310
  workingDirectory: process.cwd(),
301
311
  githubToken: "ghp_...", // optional, alternative to useLoggedInUser
302
312
  cliArgs: ["--allow-all"], // extra CLI flags for the subprocess
313
+ env: { PATH: "/custom/bin" }, // custom env vars for subprocess
303
314
  });
304
315
  ```
305
316
 
@@ -328,11 +339,14 @@ const service = createClaudeService({
328
339
  cliPath: "/path/to/claude", // optional custom CLI path
329
340
  workingDirectory: process.cwd(),
330
341
  maxTurns: 10,
342
+ env: { CLAUDE_CONFIG_DIR: "/custom/config" }, // custom env vars for subprocess
331
343
  });
332
344
  ```
333
345
 
334
346
  `supervisor.onAskUser` is not supported by the Claude backend; a warning is emitted if set.
335
347
 
348
+ When `supervisor.onPermission` is set, the Claude backend automatically sets `permissionMode: "default"` so the CLI invokes the callback instead of using built-in rules.
349
+
336
350
  ### Vercel AI (OpenRouter / OpenAI-compatible)
337
351
 
338
352
  ```typescript
@@ -132,6 +132,10 @@ var BaseAgent = class {
132
132
  this.abortController.abort();
133
133
  }
134
134
  }
135
+ /** Default interrupt — falls back to abort(). Backends may override with graceful shutdown. */
136
+ async interrupt() {
137
+ this.abort();
138
+ }
135
139
  getState() {
136
140
  return this.state;
137
141
  }
@@ -589,6 +593,7 @@ var ClaudeAgent = class extends BaseAgent {
589
593
  canUseTool;
590
594
  isPersistent;
591
595
  _sessionId;
596
+ activeQuery = null;
592
597
  constructor(config, options) {
593
598
  super(config);
594
599
  this.options = options;
@@ -604,10 +609,25 @@ var ClaudeAgent = class extends BaseAgent {
604
609
  get sessionId() {
605
610
  return this._sessionId;
606
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
+ }
607
622
  /** Clear persistent session state after an error so next call starts fresh */
608
623
  clearPersistentSession() {
609
624
  this._sessionId = void 0;
610
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
+ }
611
631
  buildQueryOptions(signal) {
612
632
  const ac = new AbortController();
613
633
  signal.addEventListener("abort", () => ac.abort(), { once: true });
@@ -627,8 +647,15 @@ var ClaudeAgent = class extends BaseAgent {
627
647
  if (this.config.systemPrompt) {
628
648
  opts.systemPrompt = this.config.systemPrompt;
629
649
  }
630
- if (this.options.oauthToken) {
631
- opts.env = { ...process.env, CLAUDE_CODE_OAUTH_TOKEN: this.options.oauthToken };
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";
632
659
  }
633
660
  return opts;
634
661
  }
@@ -653,6 +680,7 @@ var ClaudeAgent = class extends BaseAgent {
653
680
  const toolResultCapture = /* @__PURE__ */ new Map();
654
681
  opts = await this.buildMcpConfig(opts, toolResultCapture);
655
682
  const q = sdk.query({ prompt, options: opts });
683
+ this.activeQuery = q;
656
684
  const toolCalls = [];
657
685
  let output = null;
658
686
  let usage;
@@ -702,6 +730,8 @@ var ClaudeAgent = class extends BaseAgent {
702
730
  if (this.isPersistent) this.clearPersistentSession();
703
731
  if (signal.aborted) throw new AbortError();
704
732
  throw e;
733
+ } finally {
734
+ this.activeQuery = null;
705
735
  }
706
736
  return {
707
737
  output,
@@ -728,6 +758,7 @@ var ClaudeAgent = class extends BaseAgent {
728
758
  schema: jsonSchema
729
759
  };
730
760
  const q = sdk.query({ prompt, options: opts });
761
+ this.activeQuery = q;
731
762
  const toolCalls = [];
732
763
  let output = null;
733
764
  let structuredOutput;
@@ -769,6 +800,8 @@ var ClaudeAgent = class extends BaseAgent {
769
800
  if (this.isPersistent) this.clearPersistentSession();
770
801
  if (signal.aborted) throw new AbortError();
771
802
  throw e;
803
+ } finally {
804
+ this.activeQuery = null;
772
805
  }
773
806
  return {
774
807
  output,
@@ -790,6 +823,7 @@ var ClaudeAgent = class extends BaseAgent {
790
823
  let opts = this.buildQueryOptions(signal);
791
824
  opts = await this.buildMcpConfig(opts);
792
825
  const q = sdk.query({ prompt, options: opts });
826
+ this.activeQuery = q;
793
827
  const thinkingBlockIndices = /* @__PURE__ */ new Set();
794
828
  const toolCallTracker = new ClaudeToolCallTracker();
795
829
  try {
@@ -805,8 +839,11 @@ var ClaudeAgent = class extends BaseAgent {
805
839
  }
806
840
  if (msg.type === "result" && msg.subtype === "success") {
807
841
  const r = msg;
808
- if (this.isPersistent && r.session_id) {
809
- this._sessionId = r.session_id;
842
+ if (r.session_id) {
843
+ if (this.isPersistent) {
844
+ this._sessionId = r.session_id;
845
+ }
846
+ yield this.emitSessionInfo(r.session_id);
810
847
  }
811
848
  yield { type: "done", finalOutput: r.result };
812
849
  }
@@ -815,6 +852,8 @@ var ClaudeAgent = class extends BaseAgent {
815
852
  if (this.isPersistent) this.clearPersistentSession();
816
853
  if (signal.aborted) throw new AbortError();
817
854
  throw e;
855
+ } finally {
856
+ this.activeQuery = null;
818
857
  }
819
858
  }
820
859
  dispose() {