@link-assistant/agent 0.8.10 → 0.8.13

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
@@ -24,7 +24,7 @@ This is an MVP implementation of an OpenCode-compatible CLI agent, focused on ma
24
24
 
25
25
  - ✅ **JSON Input/Output**: Compatible with `opencode run --format json --model opencode/grok-code`
26
26
  - ✅ **Plain Text Input**: Also accepts plain text messages (auto-converted to JSON format)
27
- - ✅ **Flexible Model Selection**: Defaults to free OpenCode Zen Grok Code Fast 1, supports [OpenCode Zen](https://opencode.ai/docs/zen/), [Claude OAuth](../docs/claude-oauth.md), and [Groq](../docs/groq.md) providers
27
+ - ✅ **Flexible Model Selection**: Defaults to free OpenCode Zen Grok Code Fast 1, supports [OpenCode Zen](https://opencode.ai/docs/zen/), [Claude OAuth](../docs/claude-oauth.md), [Groq](../docs/groq.md), and [OpenRouter](../docs/openrouter.md) providers
28
28
  - ✅ **No Restrictions**: Fully unrestricted file system and command execution access (no sandbox)
29
29
  - ✅ **Minimal Footprint**: Built with Bun.sh for maximum efficiency
30
30
  - ✅ **Full Tool Support**: 13 tools including websearch, codesearch, batch - all enabled by default
@@ -59,6 +59,38 @@ bun add @link-assistant/agent
59
59
 
60
60
  After installation, the `agent` command will be available globally.
61
61
 
62
+ ## Uninstallation
63
+
64
+ ### Uninstalling the Agent
65
+
66
+ ```bash
67
+ # Remove the globally installed package
68
+ bun remove -g @link-assistant/agent
69
+
70
+ # Or if installed locally in your project
71
+ bun remove @link-assistant/agent
72
+ ```
73
+
74
+ ### Uninstalling Bun
75
+
76
+ If you need to completely remove Bun from your system:
77
+
78
+ ```bash
79
+ # Remove the Bun binary and installation directory
80
+ rm -rf ~/.bun
81
+
82
+ # Remove the Bun cache (optional)
83
+ rm -rf ~/.bun/install/cache
84
+ ```
85
+
86
+ After removing the `~/.bun` directory, you may also need to remove Bun from your shell configuration. Check and remove lines referencing `~/.bun/bin` from:
87
+
88
+ - `~/.bashrc`
89
+ - `~/.zshrc`
90
+ - `~/.config/fish/config.fish`
91
+
92
+ Or the corresponding configuration file for your shell.
93
+
62
94
  ## Usage
63
95
 
64
96
  ### Simplest Examples
@@ -116,6 +148,11 @@ echo "hi" | agent --model opencode/gemini-3-pro # Gemini 3 Pro
116
148
  echo "hi" | agent --model groq/llama-3.3-70b-versatile # Llama 3.3 70B
117
149
  echo "hi" | agent --model groq/llama-3.1-8b-instant # Llama 3.1 8B (fast)
118
150
 
151
+ # OpenRouter models (requires OPENROUTER_API_KEY)
152
+ echo "hi" | agent --model openrouter/anthropic/claude-sonnet-4 # Claude via OpenRouter
153
+ echo "hi" | agent --model openrouter/openai/gpt-4o # GPT-4o via OpenRouter
154
+ echo "hi" | agent --model openrouter/meta-llama/llama-3.3-70b # Llama via OpenRouter
155
+
119
156
  # Anthropic direct (requires ANTHROPIC_API_KEY)
120
157
  echo "hi" | agent --model anthropic/claude-sonnet-4-5 # Claude Sonnet 4.5
121
158
  echo "hi" | agent --model anthropic/claude-opus-4-1 # Claude Opus 4.1
@@ -138,6 +175,7 @@ echo "hi" | agent --model github-copilot/gpt-4o # Uses Copilot
138
175
 
139
176
  See [MODELS.md](../MODELS.md) for complete list of available models and pricing.
140
177
  See [docs/groq.md](../docs/groq.md) for Groq provider documentation.
178
+ See [docs/openrouter.md](../docs/openrouter.md) for OpenRouter provider documentation.
141
179
  See [docs/claude-oauth.md](../docs/claude-oauth.md) for Claude OAuth provider documentation.
142
180
 
143
181
  ### Direct Prompt Mode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/agent",
3
- "version": "0.8.10",
3
+ "version": "0.8.13",
4
4
  "description": "A minimal, public domain AI CLI agent compatible with OpenCode's JSON interface. Bun-only runtime.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -58,6 +58,21 @@ export namespace MessageV2 {
58
58
  typeof SocketConnectionError.Schema
59
59
  >;
60
60
 
61
+ /**
62
+ * Timeout error - caused by AbortSignal.timeout() firing when an API request
63
+ * takes too long. These are DOMException with name === 'TimeoutError'.
64
+ * These errors are transient and should be retried with increasing intervals.
65
+ * See: https://github.com/link-assistant/agent/issues/142
66
+ */
67
+ export const TimeoutError = NamedError.create(
68
+ 'TimeoutError',
69
+ z.object({
70
+ message: z.string(),
71
+ isRetryable: z.literal(true),
72
+ })
73
+ );
74
+ export type TimeoutError = z.infer<typeof TimeoutError.Schema>;
75
+
61
76
  const PartBase = z.object({
62
77
  id: z.string(),
63
78
  sessionID: z.string(),
@@ -782,6 +797,11 @@ export namespace MessageV2 {
782
797
  cause: e,
783
798
  }
784
799
  ).toObject();
800
+ case e instanceof DOMException && e.name === 'TimeoutError':
801
+ return new MessageV2.TimeoutError(
802
+ { message: e.message, isRetryable: true },
803
+ { cause: e }
804
+ ).toObject();
785
805
  case MessageV2.OutputLengthError.isInstance(e):
786
806
  return e;
787
807
  case LoadAPIKeyError.isInstance(e):
@@ -816,6 +836,18 @@ export namespace MessageV2 {
816
836
  { cause: e }
817
837
  ).toObject();
818
838
  }
839
+ // Detect timeout errors from various sources
840
+ // See: https://github.com/link-assistant/agent/issues/142
841
+ const isTimeoutError =
842
+ message.includes('The operation timed out') ||
843
+ message.includes('timed out') ||
844
+ e.name === 'TimeoutError';
845
+ if (isTimeoutError) {
846
+ return new MessageV2.TimeoutError(
847
+ { message, isRetryable: true },
848
+ { cause: e }
849
+ ).toObject();
850
+ }
819
851
  return new NamedError.Unknown(
820
852
  { message: e.toString() },
821
853
  { cause: e }
@@ -326,21 +326,31 @@ export namespace SessionProcessor {
326
326
  providerID: input.providerID,
327
327
  });
328
328
 
329
- // Check if error is retryable (APIError or SocketConnectionError)
329
+ // Check if error is retryable (APIError, SocketConnectionError, or TimeoutError)
330
330
  const isRetryableAPIError =
331
331
  error?.name === 'APIError' && error.data.isRetryable;
332
332
  const isRetryableSocketError =
333
333
  error?.name === 'SocketConnectionError' &&
334
334
  error.data.isRetryable &&
335
335
  attempt < SessionRetry.SOCKET_ERROR_MAX_RETRIES;
336
+ const isRetryableTimeoutError =
337
+ error?.name === 'TimeoutError' &&
338
+ error.data.isRetryable &&
339
+ attempt < SessionRetry.TIMEOUT_MAX_RETRIES;
336
340
 
337
- if (isRetryableAPIError || isRetryableSocketError) {
341
+ if (
342
+ isRetryableAPIError ||
343
+ isRetryableSocketError ||
344
+ isRetryableTimeoutError
345
+ ) {
338
346
  attempt++;
339
- // Use socket-specific delay for socket errors
347
+ // Use error-specific delay calculation
340
348
  const delay =
341
349
  error?.name === 'SocketConnectionError'
342
350
  ? SessionRetry.socketErrorDelay(attempt)
343
- : SessionRetry.delay(error, attempt);
351
+ : error?.name === 'TimeoutError'
352
+ ? SessionRetry.timeoutDelay(attempt)
353
+ : SessionRetry.delay(error, attempt);
344
354
  log.info(() => ({
345
355
  message: 'retrying',
346
356
  errorType: error?.name,
@@ -13,6 +13,12 @@ export namespace SessionRetry {
13
13
  export const SOCKET_ERROR_INITIAL_DELAY = 1000; // 1 second
14
14
  export const SOCKET_ERROR_BACKOFF_FACTOR = 2;
15
15
 
16
+ // Timeout error retry configuration
17
+ // When API requests time out (AbortSignal.timeout), retry with increasing intervals
18
+ // See: https://github.com/link-assistant/agent/issues/142
19
+ export const TIMEOUT_MAX_RETRIES = 3;
20
+ export const TIMEOUT_DELAYS = [30_000, 60_000, 120_000]; // 30s, 60s, 120s
21
+
16
22
  export async function sleep(ms: number, signal: AbortSignal): Promise<void> {
17
23
  return new Promise((resolve, reject) => {
18
24
  const timeout = setTimeout(resolve, ms);
@@ -71,4 +77,14 @@ export namespace SessionRetry {
71
77
  Math.pow(SOCKET_ERROR_BACKOFF_FACTOR, attempt - 1)
72
78
  );
73
79
  }
80
+
81
+ /**
82
+ * Calculate delay for timeout error retries.
83
+ * Uses fixed intervals: 30s, 60s, 120s.
84
+ * See: https://github.com/link-assistant/agent/issues/142
85
+ */
86
+ export function timeoutDelay(attempt: number): number {
87
+ const index = Math.min(attempt - 1, TIMEOUT_DELAYS.length - 1);
88
+ return TIMEOUT_DELAYS[index];
89
+ }
74
90
  }