@link-assistant/agent 0.18.3 → 0.19.2
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 +1 -1
- package/package.json +3 -2
- package/src/agent/agent.ts +1 -1
- package/src/auth/plugins.ts +4 -1
- package/src/bun/index.ts +2 -2
- package/src/cli/cmd/mcp.ts +1 -1
- package/src/cli/cmd/run.ts +1 -2
- package/src/cli/continuous-mode.js +3 -3
- package/src/cli/error.ts +1 -1
- package/src/cli/model-config.js +20 -10
- package/src/cli/output.ts +5 -5
- package/src/command/index.ts +1 -1
- package/src/config/config.ts +345 -1116
- package/src/config/file-config.ts +1146 -0
- package/src/file/watcher.ts +3 -3
- package/src/format/index.ts +1 -1
- package/src/index.js +50 -38
- package/src/json-standard/index.ts +5 -5
- package/src/mcp/index.ts +6 -13
- package/src/project/bootstrap.ts +0 -1
- package/src/project/project.ts +0 -1
- package/src/provider/provider.ts +23 -26
- package/src/provider/retry-fetch.ts +109 -23
- package/src/session/agent.js +4 -2
- package/src/session/compaction.ts +5 -5
- package/src/session/index.ts +19 -19
- package/src/session/processor.ts +4 -4
- package/src/session/prompt.ts +5 -5
- package/src/session/retry.ts +9 -9
- package/src/session/summary.ts +8 -8
- package/src/session/system.ts +1 -1
- package/src/snapshot/index.ts +1 -1
- package/src/storage/storage.ts +13 -2
- package/src/tool/read.ts +4 -3
- package/src/tool/registry.ts +1 -2
- package/src/tool/websearch.ts +1 -1
- package/src/util/log-lazy.ts +9 -11
- package/src/util/log.ts +9 -8
- package/src/util/verbose-fetch.ts +42 -6
- package/src/flag/flag.ts +0 -212
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Log } from './log';
|
|
2
|
-
import {
|
|
2
|
+
import { isVerbose } from '../config/config';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Shared verbose HTTP fetch wrapper.
|
|
@@ -14,7 +14,7 @@ import { Flag } from '../flag/flag';
|
|
|
14
14
|
* - Logs HTTP errors: stack trace, error cause chain
|
|
15
15
|
* - Sequential call numbering for correlation
|
|
16
16
|
* - Error-resilient: logging failures never break the actual HTTP request
|
|
17
|
-
* - Runtime verbose check: respects
|
|
17
|
+
* - Runtime verbose check: respects isVerbose() at call time (with env var fallback)
|
|
18
18
|
*
|
|
19
19
|
* @see https://github.com/link-assistant/agent/issues/215
|
|
20
20
|
*/
|
|
@@ -24,6 +24,21 @@ const log = Log.create({ service: 'http' });
|
|
|
24
24
|
/** Global call counter shared across all verbose fetch wrappers */
|
|
25
25
|
let globalHttpCallCount = 0;
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Track pending async stream log operations (#231).
|
|
29
|
+
* When the process exits while stream logging is in progress, we log a warning
|
|
30
|
+
* so missing HTTP response bodies are visible in the logs rather than silently lost.
|
|
31
|
+
*/
|
|
32
|
+
let pendingStreamLogs = 0;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get the current count of pending stream log operations.
|
|
36
|
+
* Useful for diagnostics and testing.
|
|
37
|
+
*/
|
|
38
|
+
export function getPendingStreamLogCount(): number {
|
|
39
|
+
return pendingStreamLogs;
|
|
40
|
+
}
|
|
41
|
+
|
|
27
42
|
/**
|
|
28
43
|
* Sanitize HTTP headers by masking sensitive values.
|
|
29
44
|
* Masks authorization, x-api-key, and api-key headers.
|
|
@@ -98,7 +113,7 @@ export interface VerboseFetchOptions {
|
|
|
98
113
|
/**
|
|
99
114
|
* Wrap a fetch function with verbose HTTP logging.
|
|
100
115
|
*
|
|
101
|
-
* When
|
|
116
|
+
* When isVerbose() returns true, logs all HTTP requests and responses
|
|
102
117
|
* as JSON objects. When verbose is false, returns a no-op passthrough.
|
|
103
118
|
*
|
|
104
119
|
* All logging is wrapped in try/catch so it never breaks the actual HTTP request.
|
|
@@ -121,8 +136,11 @@ export function createVerboseFetch(
|
|
|
121
136
|
input: RequestInfo | URL,
|
|
122
137
|
init?: RequestInit
|
|
123
138
|
): Promise<Response> => {
|
|
124
|
-
// Check verbose flag at call time
|
|
125
|
-
|
|
139
|
+
// Check verbose flag at call time, with env var fallback for resilience.
|
|
140
|
+
// Uses isVerbose() which checks both the in-memory flag and environment
|
|
141
|
+
// variables, preventing silent logging loss when the flag state is disrupted.
|
|
142
|
+
// See: https://github.com/link-assistant/agent/issues/227
|
|
143
|
+
if (!isVerbose()) {
|
|
126
144
|
return innerFetch(input, init);
|
|
127
145
|
}
|
|
128
146
|
|
|
@@ -193,7 +211,8 @@ export function createVerboseFetch(
|
|
|
193
211
|
if (isStreaming) {
|
|
194
212
|
const [sdkStream, logStream] = response.body.tee();
|
|
195
213
|
|
|
196
|
-
// Consume log stream asynchronously
|
|
214
|
+
// Consume log stream asynchronously, tracking pending operations (#231)
|
|
215
|
+
pendingStreamLogs++;
|
|
197
216
|
(async () => {
|
|
198
217
|
try {
|
|
199
218
|
const reader = logStream.getReader();
|
|
@@ -222,6 +241,8 @@ export function createVerboseFetch(
|
|
|
222
241
|
});
|
|
223
242
|
} catch {
|
|
224
243
|
// Ignore logging errors
|
|
244
|
+
} finally {
|
|
245
|
+
pendingStreamLogs--;
|
|
225
246
|
}
|
|
226
247
|
})();
|
|
227
248
|
|
|
@@ -301,3 +322,18 @@ export function getHttpCallCount(): number {
|
|
|
301
322
|
export function resetHttpCallCount(): void {
|
|
302
323
|
globalHttpCallCount = 0;
|
|
303
324
|
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Register a process exit handler that warns about pending stream log operations.
|
|
328
|
+
* Call this once at startup when verbose mode is enabled (#231).
|
|
329
|
+
*/
|
|
330
|
+
export function registerPendingStreamLogExitHandler(): void {
|
|
331
|
+
process.once('exit', () => {
|
|
332
|
+
if (pendingStreamLogs > 0) {
|
|
333
|
+
// Use stderr directly since the process is exiting and log infrastructure may be unavailable
|
|
334
|
+
process.stderr.write(
|
|
335
|
+
`[verbose] warning: ${pendingStreamLogs} HTTP stream response log(s) were still pending at process exit — response bodies may be missing from logs\n`
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}
|
package/src/flag/flag.ts
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
export namespace Flag {
|
|
2
|
-
// Helper to check env vars with new prefix first, then fall back to old prefix for backwards compatibility
|
|
3
|
-
function getEnv(newKey: string, oldKey: string): string | undefined {
|
|
4
|
-
return process.env[newKey] ?? process.env[oldKey];
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function truthy(key: string) {
|
|
8
|
-
const value = process.env[key]?.toLowerCase();
|
|
9
|
-
return value === 'true' || value === '1';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function truthyCompat(newKey: string, oldKey: string): boolean {
|
|
13
|
-
const value = (getEnv(newKey, oldKey) ?? '').toLowerCase();
|
|
14
|
-
return value === 'true' || value === '1';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// LINK_ASSISTANT_AGENT_AUTO_SHARE removed - no sharing support
|
|
18
|
-
export const OPENCODE_CONFIG = getEnv(
|
|
19
|
-
'LINK_ASSISTANT_AGENT_CONFIG',
|
|
20
|
-
'OPENCODE_CONFIG'
|
|
21
|
-
);
|
|
22
|
-
export const OPENCODE_CONFIG_DIR = getEnv(
|
|
23
|
-
'LINK_ASSISTANT_AGENT_CONFIG_DIR',
|
|
24
|
-
'OPENCODE_CONFIG_DIR'
|
|
25
|
-
);
|
|
26
|
-
export const OPENCODE_CONFIG_CONTENT = getEnv(
|
|
27
|
-
'LINK_ASSISTANT_AGENT_CONFIG_CONTENT',
|
|
28
|
-
'OPENCODE_CONFIG_CONTENT'
|
|
29
|
-
);
|
|
30
|
-
export const OPENCODE_DISABLE_AUTOUPDATE = truthyCompat(
|
|
31
|
-
'LINK_ASSISTANT_AGENT_DISABLE_AUTOUPDATE',
|
|
32
|
-
'OPENCODE_DISABLE_AUTOUPDATE'
|
|
33
|
-
);
|
|
34
|
-
export const OPENCODE_DISABLE_PRUNE = truthyCompat(
|
|
35
|
-
'LINK_ASSISTANT_AGENT_DISABLE_PRUNE',
|
|
36
|
-
'OPENCODE_DISABLE_PRUNE'
|
|
37
|
-
);
|
|
38
|
-
export const OPENCODE_ENABLE_EXPERIMENTAL_MODELS = truthyCompat(
|
|
39
|
-
'LINK_ASSISTANT_AGENT_ENABLE_EXPERIMENTAL_MODELS',
|
|
40
|
-
'OPENCODE_ENABLE_EXPERIMENTAL_MODELS'
|
|
41
|
-
);
|
|
42
|
-
export const OPENCODE_DISABLE_AUTOCOMPACT = truthyCompat(
|
|
43
|
-
'LINK_ASSISTANT_AGENT_DISABLE_AUTOCOMPACT',
|
|
44
|
-
'OPENCODE_DISABLE_AUTOCOMPACT'
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
// Experimental
|
|
48
|
-
export const OPENCODE_EXPERIMENTAL = truthyCompat(
|
|
49
|
-
'LINK_ASSISTANT_AGENT_EXPERIMENTAL',
|
|
50
|
-
'OPENCODE_EXPERIMENTAL'
|
|
51
|
-
);
|
|
52
|
-
export const OPENCODE_EXPERIMENTAL_WATCHER =
|
|
53
|
-
OPENCODE_EXPERIMENTAL ||
|
|
54
|
-
truthyCompat(
|
|
55
|
-
'LINK_ASSISTANT_AGENT_EXPERIMENTAL_WATCHER',
|
|
56
|
-
'OPENCODE_EXPERIMENTAL_WATCHER'
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
// Verbose mode - enables detailed logging of API requests
|
|
60
|
-
export let OPENCODE_VERBOSE = truthyCompat(
|
|
61
|
-
'LINK_ASSISTANT_AGENT_VERBOSE',
|
|
62
|
-
'OPENCODE_VERBOSE'
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
// Dry run mode - simulate operations without making actual API calls or changes
|
|
66
|
-
export let OPENCODE_DRY_RUN = truthyCompat(
|
|
67
|
-
'LINK_ASSISTANT_AGENT_DRY_RUN',
|
|
68
|
-
'OPENCODE_DRY_RUN'
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
// Title generation configuration
|
|
72
|
-
// When disabled, sessions will use default "New session - {timestamp}" titles
|
|
73
|
-
// This saves tokens and prevents rate limit issues with free tier models
|
|
74
|
-
// See: https://github.com/link-assistant/agent/issues/157
|
|
75
|
-
export let GENERATE_TITLE = truthyCompat(
|
|
76
|
-
'LINK_ASSISTANT_AGENT_GENERATE_TITLE',
|
|
77
|
-
'AGENT_GENERATE_TITLE'
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
// Allow setting title generation mode programmatically (e.g., from CLI --generate-title flag)
|
|
81
|
-
export function setGenerateTitle(value: boolean) {
|
|
82
|
-
GENERATE_TITLE = value;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Output response model information in step-finish parts
|
|
86
|
-
// Enabled by default - includes model info (providerID, requestedModelID, respondedModelID) in output
|
|
87
|
-
// Can be disabled with AGENT_OUTPUT_RESPONSE_MODEL=false
|
|
88
|
-
// See: https://github.com/link-assistant/agent/issues/179
|
|
89
|
-
export let OUTPUT_RESPONSE_MODEL = (() => {
|
|
90
|
-
const value = (
|
|
91
|
-
getEnv(
|
|
92
|
-
'LINK_ASSISTANT_AGENT_OUTPUT_RESPONSE_MODEL',
|
|
93
|
-
'AGENT_OUTPUT_RESPONSE_MODEL'
|
|
94
|
-
) ?? ''
|
|
95
|
-
).toLowerCase();
|
|
96
|
-
if (value === 'false' || value === '0') return false;
|
|
97
|
-
return true; // Default to true
|
|
98
|
-
})();
|
|
99
|
-
|
|
100
|
-
// Allow setting output-response-model mode programmatically (e.g., from CLI --output-response-model flag)
|
|
101
|
-
export function setOutputResponseModel(value: boolean) {
|
|
102
|
-
OUTPUT_RESPONSE_MODEL = value;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Session summarization configuration
|
|
106
|
-
// Enabled by default - generates AI-powered session summaries using the same model
|
|
107
|
-
// Can be disabled with --no-summarize-session or AGENT_SUMMARIZE_SESSION=false
|
|
108
|
-
// See: https://github.com/link-assistant/agent/issues/217
|
|
109
|
-
export let SUMMARIZE_SESSION = (() => {
|
|
110
|
-
const value = (
|
|
111
|
-
getEnv(
|
|
112
|
-
'LINK_ASSISTANT_AGENT_SUMMARIZE_SESSION',
|
|
113
|
-
'AGENT_SUMMARIZE_SESSION'
|
|
114
|
-
) ?? ''
|
|
115
|
-
).toLowerCase();
|
|
116
|
-
if (value === 'false' || value === '0') return false;
|
|
117
|
-
return true; // Default to true
|
|
118
|
-
})();
|
|
119
|
-
|
|
120
|
-
// Allow setting summarize-session mode programmatically (e.g., from CLI --summarize-session flag)
|
|
121
|
-
export function setSummarizeSession(value: boolean) {
|
|
122
|
-
SUMMARIZE_SESSION = value;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Retry timeout configuration
|
|
126
|
-
// Maximum total time to keep retrying for the same error type (default: 7 days in seconds)
|
|
127
|
-
// For different error types, the timer resets
|
|
128
|
-
// See: https://github.com/link-assistant/agent/issues/157
|
|
129
|
-
export function RETRY_TIMEOUT(): number {
|
|
130
|
-
const val = getEnv(
|
|
131
|
-
'LINK_ASSISTANT_AGENT_RETRY_TIMEOUT',
|
|
132
|
-
'AGENT_RETRY_TIMEOUT'
|
|
133
|
-
);
|
|
134
|
-
return val ? parseInt(val, 10) : 604800; // 7 days in seconds
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Maximum delay for a single retry attempt (default: 20 minutes in milliseconds)
|
|
138
|
-
export function MAX_RETRY_DELAY(): number {
|
|
139
|
-
const val = getEnv(
|
|
140
|
-
'LINK_ASSISTANT_AGENT_MAX_RETRY_DELAY',
|
|
141
|
-
'AGENT_MAX_RETRY_DELAY'
|
|
142
|
-
);
|
|
143
|
-
return val ? parseInt(val, 10) * 1000 : 1200000; // 20 minutes in ms
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Minimum retry interval to prevent rapid retries (default: 30 seconds)
|
|
147
|
-
// This ensures we don't hammer the API with rapid retry attempts
|
|
148
|
-
// See: https://github.com/link-assistant/agent/issues/167
|
|
149
|
-
export function MIN_RETRY_INTERVAL(): number {
|
|
150
|
-
const val = getEnv(
|
|
151
|
-
'LINK_ASSISTANT_AGENT_MIN_RETRY_INTERVAL',
|
|
152
|
-
'AGENT_MIN_RETRY_INTERVAL'
|
|
153
|
-
);
|
|
154
|
-
return val ? parseInt(val, 10) * 1000 : 30000; // 30 seconds in ms
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Stream timeout configuration
|
|
158
|
-
// chunkMs: timeout between stream chunks - detects stalled streams (default: 2 minutes)
|
|
159
|
-
// stepMs: timeout for each individual LLM step (default: 10 minutes)
|
|
160
|
-
export function STREAM_CHUNK_TIMEOUT_MS(): number {
|
|
161
|
-
const val = getEnv(
|
|
162
|
-
'LINK_ASSISTANT_AGENT_STREAM_CHUNK_TIMEOUT_MS',
|
|
163
|
-
'AGENT_STREAM_CHUNK_TIMEOUT_MS'
|
|
164
|
-
);
|
|
165
|
-
return val ? parseInt(val, 10) : 120_000;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function STREAM_STEP_TIMEOUT_MS(): number {
|
|
169
|
-
const val = getEnv(
|
|
170
|
-
'LINK_ASSISTANT_AGENT_STREAM_STEP_TIMEOUT_MS',
|
|
171
|
-
'AGENT_STREAM_STEP_TIMEOUT_MS'
|
|
172
|
-
);
|
|
173
|
-
return val ? parseInt(val, 10) : 600_000;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Compact JSON mode - output JSON on single lines (NDJSON format)
|
|
177
|
-
// Enabled by AGENT_CLI_COMPACT env var or --compact-json flag
|
|
178
|
-
// Uses getter to check env var at runtime for tests
|
|
179
|
-
let _compactJson: boolean | null = null;
|
|
180
|
-
|
|
181
|
-
export function COMPACT_JSON(): boolean {
|
|
182
|
-
if (_compactJson !== null) return _compactJson;
|
|
183
|
-
return (
|
|
184
|
-
truthy('AGENT_CLI_COMPACT') ||
|
|
185
|
-
truthyCompat('LINK_ASSISTANT_AGENT_COMPACT_JSON', 'OPENCODE_COMPACT_JSON')
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Allow setting verbose mode programmatically (e.g., from CLI --verbose flag)
|
|
190
|
-
export function setVerbose(value: boolean) {
|
|
191
|
-
OPENCODE_VERBOSE = value;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Allow setting dry run mode programmatically (e.g., from CLI --dry-run flag)
|
|
195
|
-
export function setDryRun(value: boolean) {
|
|
196
|
-
OPENCODE_DRY_RUN = value;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Allow setting compact JSON mode programmatically (e.g., from CLI --compact-json flag)
|
|
200
|
-
export function setCompactJson(value: boolean) {
|
|
201
|
-
_compactJson = value;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Retry on rate limits - when disabled, 429 responses are returned immediately without retrying
|
|
205
|
-
// Enabled by default. Use --no-retry-on-rate-limits in integration tests to avoid waiting for rate limits.
|
|
206
|
-
export let RETRY_ON_RATE_LIMITS = true;
|
|
207
|
-
|
|
208
|
-
// Allow setting retry-on-rate-limits mode programmatically (e.g., from CLI --retry-on-rate-limits flag)
|
|
209
|
-
export function setRetryOnRateLimits(value: boolean) {
|
|
210
|
-
RETRY_ON_RATE_LIMITS = value;
|
|
211
|
-
}
|
|
212
|
-
}
|