@link-assistant/agent 0.5.3 → 0.6.1
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/package.json +4 -3
- package/src/auth/claude-oauth.ts +50 -24
- package/src/auth/plugins.ts +245 -28
- package/src/bun/index.ts +33 -27
- package/src/bus/index.ts +3 -5
- package/src/config/config.ts +39 -22
- package/src/file/ripgrep.ts +1 -1
- package/src/file/time.ts +1 -1
- package/src/file/watcher.ts +10 -5
- package/src/format/index.ts +12 -10
- package/src/index.js +30 -35
- package/src/mcp/index.ts +32 -15
- package/src/patch/index.ts +8 -4
- package/src/project/project.ts +1 -1
- package/src/project/state.ts +15 -7
- package/src/provider/models.ts +4 -5
- package/src/provider/provider.ts +29 -21
- package/src/server/server.ts +4 -5
- package/src/session/agent.js +16 -2
- package/src/session/compaction.ts +4 -6
- package/src/session/index.ts +2 -2
- package/src/session/processor.ts +3 -7
- package/src/session/prompt.ts +78 -49
- package/src/session/revert.ts +1 -1
- package/src/session/summary.ts +2 -2
- package/src/snapshot/index.ts +27 -12
- package/src/storage/storage.ts +18 -18
- package/src/util/log-lazy.ts +291 -0
- package/src/util/log.ts +205 -28
package/src/project/state.ts
CHANGED
|
@@ -36,16 +36,20 @@ export namespace State {
|
|
|
36
36
|
const entries = recordsByKey.get(key);
|
|
37
37
|
if (!entries) return;
|
|
38
38
|
|
|
39
|
-
log.info(
|
|
39
|
+
log.info(() => ({
|
|
40
|
+
message: 'waiting for state disposal to complete',
|
|
41
|
+
key,
|
|
42
|
+
}));
|
|
40
43
|
|
|
41
44
|
let disposalFinished = false;
|
|
42
45
|
|
|
43
46
|
setTimeout(() => {
|
|
44
47
|
if (!disposalFinished) {
|
|
45
|
-
log.warn(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
log.warn(() => ({
|
|
49
|
+
message:
|
|
50
|
+
'state disposal is taking an unusually long time - if it does not complete in a reasonable time, please report this as a bug',
|
|
51
|
+
key,
|
|
52
|
+
}));
|
|
49
53
|
}
|
|
50
54
|
}, 10000).unref();
|
|
51
55
|
|
|
@@ -56,7 +60,11 @@ export namespace State {
|
|
|
56
60
|
const task = Promise.resolve(entry.state)
|
|
57
61
|
.then((state) => entry.dispose!(state))
|
|
58
62
|
.catch((error) => {
|
|
59
|
-
log.error(
|
|
63
|
+
log.error(() => ({
|
|
64
|
+
message: 'Error while disposing state',
|
|
65
|
+
error,
|
|
66
|
+
key,
|
|
67
|
+
}));
|
|
60
68
|
});
|
|
61
69
|
|
|
62
70
|
tasks.push(task);
|
|
@@ -64,6 +72,6 @@ export namespace State {
|
|
|
64
72
|
await Promise.all(tasks);
|
|
65
73
|
recordsByKey.delete(key);
|
|
66
74
|
disposalFinished = true;
|
|
67
|
-
log.info('state disposal completed',
|
|
75
|
+
log.info(() => ({ message: 'state disposal completed', key }));
|
|
68
76
|
}
|
|
69
77
|
}
|
package/src/provider/models.ts
CHANGED
|
@@ -78,18 +78,17 @@ export namespace ModelsDev {
|
|
|
78
78
|
|
|
79
79
|
export async function refresh() {
|
|
80
80
|
const file = Bun.file(filepath);
|
|
81
|
-
log.info('refreshing',
|
|
82
|
-
file,
|
|
83
|
-
});
|
|
81
|
+
log.info(() => ({ message: 'refreshing', file }));
|
|
84
82
|
const result = await fetch('https://models.dev/api.json', {
|
|
85
83
|
headers: {
|
|
86
84
|
'User-Agent': 'agent-cli/1.0.0',
|
|
87
85
|
},
|
|
88
86
|
signal: AbortSignal.timeout(10 * 1000),
|
|
89
87
|
}).catch((e) => {
|
|
90
|
-
log.error(
|
|
88
|
+
log.error(() => ({
|
|
89
|
+
message: 'Failed to fetch models.dev',
|
|
91
90
|
error: e,
|
|
92
|
-
});
|
|
91
|
+
}));
|
|
93
92
|
});
|
|
94
93
|
if (result && result.ok) await Bun.write(file, await result.text());
|
|
95
94
|
}
|
package/src/provider/provider.ts
CHANGED
|
@@ -37,7 +37,7 @@ export namespace Provider {
|
|
|
37
37
|
// Check if OAuth credentials are available via the auth plugin
|
|
38
38
|
const auth = await Auth.get('anthropic');
|
|
39
39
|
if (auth?.type === 'oauth') {
|
|
40
|
-
log.info('using anthropic oauth credentials');
|
|
40
|
+
log.info(() => ({ message: 'using anthropic oauth credentials' }));
|
|
41
41
|
const loaderFn = await AuthPlugins.getLoader('anthropic');
|
|
42
42
|
if (loaderFn) {
|
|
43
43
|
const result = await loaderFn(() => Auth.get('anthropic'), input);
|
|
@@ -330,7 +330,7 @@ export namespace Provider {
|
|
|
330
330
|
google: async (input) => {
|
|
331
331
|
const auth = await Auth.get('google');
|
|
332
332
|
if (auth?.type === 'oauth') {
|
|
333
|
-
log.info('using google oauth credentials');
|
|
333
|
+
log.info(() => ({ message: 'using google oauth credentials' }));
|
|
334
334
|
const loaderFn = await AuthPlugins.getLoader('google');
|
|
335
335
|
if (loaderFn) {
|
|
336
336
|
const result = await loaderFn(() => Auth.get('google'), input);
|
|
@@ -355,7 +355,9 @@ export namespace Provider {
|
|
|
355
355
|
'github-copilot': async (input) => {
|
|
356
356
|
const auth = await Auth.get('github-copilot');
|
|
357
357
|
if (auth?.type === 'oauth') {
|
|
358
|
-
log.info(
|
|
358
|
+
log.info(() => ({
|
|
359
|
+
message: 'using github copilot oauth credentials',
|
|
360
|
+
}));
|
|
359
361
|
const loaderFn = await AuthPlugins.getLoader('github-copilot');
|
|
360
362
|
if (loaderFn) {
|
|
361
363
|
const result = await loaderFn(
|
|
@@ -383,7 +385,9 @@ export namespace Provider {
|
|
|
383
385
|
'github-copilot-enterprise': async (input) => {
|
|
384
386
|
const auth = await Auth.get('github-copilot-enterprise');
|
|
385
387
|
if (auth?.type === 'oauth') {
|
|
386
|
-
log.info(
|
|
388
|
+
log.info(() => ({
|
|
389
|
+
message: 'using github copilot enterprise oauth credentials',
|
|
390
|
+
}));
|
|
387
391
|
const loaderFn = await AuthPlugins.getLoader('github-copilot');
|
|
388
392
|
if (loaderFn) {
|
|
389
393
|
const result = await loaderFn(
|
|
@@ -435,7 +439,10 @@ export namespace Provider {
|
|
|
435
439
|
return { autoload: false };
|
|
436
440
|
}
|
|
437
441
|
|
|
438
|
-
log.info(
|
|
442
|
+
log.info(() => ({
|
|
443
|
+
message: 'using claude oauth credentials',
|
|
444
|
+
source: tokenSource,
|
|
445
|
+
}));
|
|
439
446
|
|
|
440
447
|
// Create authenticated fetch with Bearer token and OAuth beta header
|
|
441
448
|
const customFetch = ClaudeOAuth.createAuthenticatedFetch(oauthToken);
|
|
@@ -537,7 +544,7 @@ export namespace Provider {
|
|
|
537
544
|
// Maps `${provider}/${key}` to the provider’s actual model ID for custom aliases.
|
|
538
545
|
const realIdByKey = new Map<string, string>();
|
|
539
546
|
|
|
540
|
-
log.info('init');
|
|
547
|
+
log.info(() => ({ message: 'init' }));
|
|
541
548
|
|
|
542
549
|
function mergeProvider(
|
|
543
550
|
id: string,
|
|
@@ -783,7 +790,7 @@ export namespace Provider {
|
|
|
783
790
|
delete providers[providerID];
|
|
784
791
|
continue;
|
|
785
792
|
}
|
|
786
|
-
log.info('found',
|
|
793
|
+
log.info(() => ({ message: 'found', providerID }));
|
|
787
794
|
}
|
|
788
795
|
|
|
789
796
|
return {
|
|
@@ -818,19 +825,21 @@ export namespace Provider {
|
|
|
818
825
|
|
|
819
826
|
let installedPath: string;
|
|
820
827
|
if (!pkg.startsWith('file://')) {
|
|
821
|
-
log.info(
|
|
828
|
+
log.info(() => ({
|
|
829
|
+
message: 'installing provider package',
|
|
822
830
|
providerID: provider.id,
|
|
823
831
|
pkg,
|
|
824
832
|
version: 'latest',
|
|
825
|
-
});
|
|
833
|
+
}));
|
|
826
834
|
installedPath = await BunProc.install(pkg, 'latest');
|
|
827
|
-
log.info(
|
|
835
|
+
log.info(() => ({
|
|
836
|
+
message: 'provider package installed successfully',
|
|
828
837
|
providerID: provider.id,
|
|
829
838
|
pkg,
|
|
830
839
|
installedPath,
|
|
831
|
-
});
|
|
840
|
+
}));
|
|
832
841
|
} else {
|
|
833
|
-
log.info('loading local provider',
|
|
842
|
+
log.info(() => ({ message: 'loading local provider', pkg }));
|
|
834
843
|
installedPath = pkg;
|
|
835
844
|
}
|
|
836
845
|
|
|
@@ -876,13 +885,14 @@ export namespace Provider {
|
|
|
876
885
|
s.sdk.set(key, loaded);
|
|
877
886
|
return loaded as SDK;
|
|
878
887
|
})().catch((e) => {
|
|
879
|
-
log.error(
|
|
888
|
+
log.error(() => ({
|
|
889
|
+
message: 'provider initialization failed',
|
|
880
890
|
providerID: provider.id,
|
|
881
891
|
pkg: model.provider?.npm ?? provider.npm ?? provider.id,
|
|
882
892
|
error: e instanceof Error ? e.message : String(e),
|
|
883
893
|
stack: e instanceof Error ? e.stack : undefined,
|
|
884
894
|
cause: e instanceof Error && e.cause ? String(e.cause) : undefined,
|
|
885
|
-
});
|
|
895
|
+
}));
|
|
886
896
|
throw new InitError({ providerID: provider.id }, { cause: e });
|
|
887
897
|
});
|
|
888
898
|
}
|
|
@@ -896,10 +906,7 @@ export namespace Provider {
|
|
|
896
906
|
const s = await state();
|
|
897
907
|
if (s.models.has(key)) return s.models.get(key)!;
|
|
898
908
|
|
|
899
|
-
log.info('getModel',
|
|
900
|
-
providerID,
|
|
901
|
-
modelID,
|
|
902
|
-
});
|
|
909
|
+
log.info(() => ({ message: 'getModel', providerID, modelID }));
|
|
903
910
|
|
|
904
911
|
const provider = s.providers[providerID];
|
|
905
912
|
if (!provider) throw new ModelNotFoundError({ providerID, modelID });
|
|
@@ -929,7 +936,7 @@ export namespace Provider {
|
|
|
929
936
|
? await provider.getModel(sdk, realID, provider.options)
|
|
930
937
|
: sdk.languageModel(realID);
|
|
931
938
|
}
|
|
932
|
-
log.info('found',
|
|
939
|
+
log.info(() => ({ message: 'found', providerID, modelID }));
|
|
933
940
|
s.models.set(key, {
|
|
934
941
|
providerID,
|
|
935
942
|
modelID,
|
|
@@ -1032,10 +1039,11 @@ export namespace Provider {
|
|
|
1032
1039
|
if (opencodeProvider) {
|
|
1033
1040
|
const [model] = sort(Object.values(opencodeProvider.info.models));
|
|
1034
1041
|
if (model) {
|
|
1035
|
-
log.info(
|
|
1042
|
+
log.info(() => ({
|
|
1043
|
+
message: 'using opencode provider as default',
|
|
1036
1044
|
provider: opencodeProvider.info.id,
|
|
1037
1045
|
model: model.id,
|
|
1038
|
-
});
|
|
1046
|
+
}));
|
|
1039
1047
|
return {
|
|
1040
1048
|
providerID: opencodeProvider.info.id,
|
|
1041
1049
|
modelID: model.id,
|
package/src/server/server.ts
CHANGED
|
@@ -55,9 +55,7 @@ export namespace Server {
|
|
|
55
55
|
export const App = lazy(() =>
|
|
56
56
|
app
|
|
57
57
|
.onError((err, c) => {
|
|
58
|
-
log.error('failed',
|
|
59
|
-
error: err,
|
|
60
|
-
});
|
|
58
|
+
log.error(() => ({ message: 'failed', error: err }));
|
|
61
59
|
if (err instanceof NamedError) {
|
|
62
60
|
let status: ContentfulStatusCode;
|
|
63
61
|
if (err instanceof Storage.NotFoundError) status = 404;
|
|
@@ -71,10 +69,11 @@ export namespace Server {
|
|
|
71
69
|
});
|
|
72
70
|
})
|
|
73
71
|
.use(async (c, next) => {
|
|
74
|
-
log.info(
|
|
72
|
+
log.info(() => ({
|
|
73
|
+
message: 'request',
|
|
75
74
|
method: c.req.method,
|
|
76
75
|
path: c.req.path,
|
|
77
|
-
});
|
|
76
|
+
}));
|
|
78
77
|
const timer = log.time('request', {
|
|
79
78
|
method: c.req.method,
|
|
80
79
|
path: c.req.path,
|
package/src/session/agent.js
CHANGED
|
@@ -96,8 +96,22 @@ export class Agent {
|
|
|
96
96
|
const errorTime = Date.now();
|
|
97
97
|
const callID = `call_${Math.floor(Math.random() * 100000000)}`;
|
|
98
98
|
|
|
99
|
-
// Log full error to stderr for debugging
|
|
100
|
-
console.error(
|
|
99
|
+
// Log full error to stderr for debugging in JSON format
|
|
100
|
+
console.error(
|
|
101
|
+
JSON.stringify({
|
|
102
|
+
log: {
|
|
103
|
+
level: 'error',
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
message: 'Tool execution error',
|
|
106
|
+
tool: tool.name,
|
|
107
|
+
error: {
|
|
108
|
+
name: error.name,
|
|
109
|
+
message: error.message,
|
|
110
|
+
stack: error.stack,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
);
|
|
101
115
|
|
|
102
116
|
// Emit tool_use event with error
|
|
103
117
|
this.emitEvent('tool_use', {
|
|
@@ -52,7 +52,7 @@ export namespace SessionCompaction {
|
|
|
52
52
|
// tool calls that are no longer relevant.
|
|
53
53
|
export async function prune(input: { sessionID: string }) {
|
|
54
54
|
if (Flag.OPENCODE_DISABLE_PRUNE) return;
|
|
55
|
-
log.info('pruning');
|
|
55
|
+
log.info(() => ({ message: 'pruning' }));
|
|
56
56
|
const msgs = await Session.messages({ sessionID: input.sessionID });
|
|
57
57
|
let total = 0;
|
|
58
58
|
let pruned = 0;
|
|
@@ -78,7 +78,7 @@ export namespace SessionCompaction {
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
-
log.info('found',
|
|
81
|
+
log.info(() => ({ message: 'found', pruned, total }));
|
|
82
82
|
if (pruned > PRUNE_MINIMUM) {
|
|
83
83
|
for (const part of toPrune) {
|
|
84
84
|
if (part.state.status === 'completed') {
|
|
@@ -86,7 +86,7 @@ export namespace SessionCompaction {
|
|
|
86
86
|
await Session.updatePart(part);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
log.info('pruned',
|
|
89
|
+
log.info(() => ({ message: 'pruned', count: toPrune.length }));
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -139,9 +139,7 @@ export namespace SessionCompaction {
|
|
|
139
139
|
const result = await processor.process(() =>
|
|
140
140
|
streamText({
|
|
141
141
|
onError(error) {
|
|
142
|
-
log.error('stream error',
|
|
143
|
-
error,
|
|
144
|
-
});
|
|
142
|
+
log.error(() => ({ message: 'stream error', error }));
|
|
145
143
|
},
|
|
146
144
|
// set to 0, we handle loop
|
|
147
145
|
maxRetries: 0,
|
package/src/session/index.ts
CHANGED
|
@@ -178,7 +178,7 @@ export namespace Session {
|
|
|
178
178
|
updated: Date.now(),
|
|
179
179
|
},
|
|
180
180
|
};
|
|
181
|
-
log.info('created', result);
|
|
181
|
+
log.info(() => ({ message: 'created', ...result }));
|
|
182
182
|
await Storage.write(['session', Instance.project.id, result.id], result);
|
|
183
183
|
Bus.publish(Event.Created, {
|
|
184
184
|
info: result,
|
|
@@ -273,7 +273,7 @@ export namespace Session {
|
|
|
273
273
|
info: session,
|
|
274
274
|
});
|
|
275
275
|
} catch (e) {
|
|
276
|
-
log.error(e);
|
|
276
|
+
log.error(() => ({ error: e }));
|
|
277
277
|
}
|
|
278
278
|
});
|
|
279
279
|
|
package/src/session/processor.ts
CHANGED
|
@@ -39,7 +39,7 @@ export namespace SessionProcessor {
|
|
|
39
39
|
return toolcalls[toolCallID];
|
|
40
40
|
},
|
|
41
41
|
async process(fn: () => StreamTextResult<Record<string, AITool>, never>) {
|
|
42
|
-
log.info('process');
|
|
42
|
+
log.info(() => ({ message: 'process' }));
|
|
43
43
|
while (true) {
|
|
44
44
|
try {
|
|
45
45
|
let currentText: MessageV2.TextPart | undefined;
|
|
@@ -305,16 +305,12 @@ export namespace SessionProcessor {
|
|
|
305
305
|
break;
|
|
306
306
|
|
|
307
307
|
default:
|
|
308
|
-
log.info('unhandled',
|
|
309
|
-
...value,
|
|
310
|
-
});
|
|
308
|
+
log.info(() => ({ message: 'unhandled', ...value }));
|
|
311
309
|
continue;
|
|
312
310
|
}
|
|
313
311
|
}
|
|
314
312
|
} catch (e) {
|
|
315
|
-
log.error('process',
|
|
316
|
-
error: e,
|
|
317
|
-
});
|
|
313
|
+
log.error(() => ({ message: 'process', error: e }));
|
|
318
314
|
const error = MessageV2.fromError(e, {
|
|
319
315
|
providerID: input.providerID,
|
|
320
316
|
});
|
package/src/session/prompt.ts
CHANGED
|
@@ -216,7 +216,7 @@ export namespace SessionPrompt {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
export function cancel(sessionID: string) {
|
|
219
|
-
log.info('cancel',
|
|
219
|
+
log.info(() => ({ message: 'cancel', sessionID }));
|
|
220
220
|
const s = state();
|
|
221
221
|
const match = s[sessionID];
|
|
222
222
|
if (!match) return;
|
|
@@ -242,7 +242,7 @@ export namespace SessionPrompt {
|
|
|
242
242
|
|
|
243
243
|
let step = 0;
|
|
244
244
|
while (true) {
|
|
245
|
-
log.info('loop',
|
|
245
|
+
log.info(() => ({ message: 'loop', step, sessionID }));
|
|
246
246
|
if (abort.aborted) break;
|
|
247
247
|
let msgs = await MessageV2.filterCompacted(MessageV2.stream(sessionID));
|
|
248
248
|
|
|
@@ -276,7 +276,7 @@ export namespace SessionPrompt {
|
|
|
276
276
|
lastAssistant.finish !== 'tool-calls' &&
|
|
277
277
|
lastUser.id < lastAssistant.id
|
|
278
278
|
) {
|
|
279
|
-
log.info('exiting loop',
|
|
279
|
+
log.info(() => ({ message: 'exiting loop', sessionID }));
|
|
280
280
|
break;
|
|
281
281
|
}
|
|
282
282
|
|
|
@@ -297,14 +297,13 @@ export namespace SessionPrompt {
|
|
|
297
297
|
lastUser.model.modelID
|
|
298
298
|
);
|
|
299
299
|
} catch (error) {
|
|
300
|
-
log.warn(
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
);
|
|
300
|
+
log.warn(() => ({
|
|
301
|
+
message:
|
|
302
|
+
'Failed to initialize specified model, falling back to default model',
|
|
303
|
+
providerID: lastUser.model.providerID,
|
|
304
|
+
modelID: lastUser.model.modelID,
|
|
305
|
+
error: error instanceof Error ? error.message : String(error),
|
|
306
|
+
}));
|
|
308
307
|
const defaultModel = await Provider.defaultModel();
|
|
309
308
|
model = await Provider.getModel(
|
|
310
309
|
defaultModel.providerID,
|
|
@@ -551,53 +550,79 @@ export namespace SessionPrompt {
|
|
|
551
550
|
);
|
|
552
551
|
const totalEstimatedTokens = systemTokens + userTokens;
|
|
553
552
|
|
|
554
|
-
log.info(
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
log.info(
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
553
|
+
log.info(() => ({
|
|
554
|
+
message: '=== VERBOSE: API Request Details ===',
|
|
555
|
+
}));
|
|
556
|
+
log.info(() => ({
|
|
557
|
+
message: 'Model',
|
|
558
|
+
model: `${model.providerID}/${model.modelID}`,
|
|
559
|
+
}));
|
|
560
|
+
log.info(() => ({ message: 'Session ID', sessionID }));
|
|
561
|
+
log.info(() => ({ message: 'Agent', agent: agent.name }));
|
|
562
|
+
log.info(() => ({
|
|
563
|
+
message: 'Temperature',
|
|
564
|
+
temperature: params.temperature ?? 'default',
|
|
565
|
+
}));
|
|
566
|
+
log.info(() => ({
|
|
567
|
+
message: 'Top P',
|
|
568
|
+
topP: params.topP ?? 'default',
|
|
569
|
+
}));
|
|
570
|
+
log.info(() => ({
|
|
571
|
+
message: 'Active Tools',
|
|
572
|
+
tools: Object.keys(tools).filter((x) => x !== 'invalid'),
|
|
573
|
+
}));
|
|
574
|
+
log.info(() => ({ message: '--- System Prompt ---' }));
|
|
566
575
|
for (let i = 0; i < system.length; i++) {
|
|
567
576
|
const tokens = Token.estimate(system[i]);
|
|
568
|
-
log.info(
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
);
|
|
577
|
+
log.info(() => ({
|
|
578
|
+
message: 'System Message',
|
|
579
|
+
index: i + 1,
|
|
580
|
+
tokens,
|
|
581
|
+
}));
|
|
582
|
+
log.info(() => ({
|
|
583
|
+
message: 'System Message Content',
|
|
584
|
+
content:
|
|
585
|
+
system[i].slice(0, 2000) +
|
|
586
|
+
(system[i].length > 2000 ? '... [truncated]' : ''),
|
|
587
|
+
}));
|
|
573
588
|
}
|
|
574
|
-
log.info('--- Token Summary ---');
|
|
575
|
-
log.info(
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
)
|
|
584
|
-
|
|
589
|
+
log.info(() => ({ message: '--- Token Summary ---' }));
|
|
590
|
+
log.info(() => ({
|
|
591
|
+
message: 'System prompt tokens (estimated)',
|
|
592
|
+
systemTokens,
|
|
593
|
+
}));
|
|
594
|
+
log.info(() => ({
|
|
595
|
+
message: 'User message tokens (estimated)',
|
|
596
|
+
userTokens,
|
|
597
|
+
}));
|
|
598
|
+
log.info(() => ({
|
|
599
|
+
message: 'Total estimated tokens',
|
|
600
|
+
totalEstimatedTokens,
|
|
601
|
+
}));
|
|
602
|
+
log.info(() => ({
|
|
603
|
+
message: 'Model context limit',
|
|
604
|
+
contextLimit: model.info?.limit?.context || 'unknown',
|
|
605
|
+
}));
|
|
606
|
+
log.info(() => ({
|
|
607
|
+
message: 'Model output limit',
|
|
608
|
+
outputLimit: model.info?.limit?.output || 'unknown',
|
|
609
|
+
}));
|
|
610
|
+
log.info(() => ({ message: '=== END VERBOSE ===' }));
|
|
585
611
|
}
|
|
586
612
|
|
|
587
613
|
const result = await processor.process(() =>
|
|
588
614
|
streamText({
|
|
589
615
|
onError(error) {
|
|
590
|
-
log.error('stream error',
|
|
591
|
-
error,
|
|
592
|
-
});
|
|
616
|
+
log.error(() => ({ message: 'stream error', error }));
|
|
593
617
|
},
|
|
594
618
|
async experimental_repairToolCall(input) {
|
|
595
619
|
const lower = input.toolCall.toolName.toLowerCase();
|
|
596
620
|
if (lower !== input.toolCall.toolName && tools[lower]) {
|
|
597
|
-
log.info(
|
|
621
|
+
log.info(() => ({
|
|
622
|
+
message: 'repairing tool call',
|
|
598
623
|
tool: input.toolCall.toolName,
|
|
599
624
|
repaired: lower,
|
|
600
|
-
});
|
|
625
|
+
}));
|
|
601
626
|
return {
|
|
602
627
|
...input.toolCall,
|
|
603
628
|
toolName: lower,
|
|
@@ -945,7 +970,7 @@ export namespace SessionPrompt {
|
|
|
945
970
|
}
|
|
946
971
|
break;
|
|
947
972
|
case 'file:':
|
|
948
|
-
log.info('file',
|
|
973
|
+
log.info(() => ({ message: 'file', mime: part.mime }));
|
|
949
974
|
// have to normalize, symbol search returns absolute paths
|
|
950
975
|
// Decode the pathname since URL constructor doesn't automatically decode it
|
|
951
976
|
const filepath = fileURLToPath(part.url);
|
|
@@ -1012,7 +1037,10 @@ export namespace SessionPrompt {
|
|
|
1012
1037
|
);
|
|
1013
1038
|
})
|
|
1014
1039
|
.catch((error) => {
|
|
1015
|
-
log.error(
|
|
1040
|
+
log.error(() => ({
|
|
1041
|
+
message: 'failed to read file',
|
|
1042
|
+
error,
|
|
1043
|
+
}));
|
|
1016
1044
|
const message =
|
|
1017
1045
|
error instanceof Error ? error.message : error.toString();
|
|
1018
1046
|
Bus.publish(Session.Event.Error, {
|
|
@@ -1376,7 +1404,7 @@ export namespace SessionPrompt {
|
|
|
1376
1404
|
*/
|
|
1377
1405
|
|
|
1378
1406
|
export async function command(input: CommandInput) {
|
|
1379
|
-
log.info('command', input);
|
|
1407
|
+
log.info(() => ({ message: 'command', ...input }));
|
|
1380
1408
|
const command = await Command.get(input.command);
|
|
1381
1409
|
const agentName = command.agent ?? input.agent ?? 'build';
|
|
1382
1410
|
|
|
@@ -1572,10 +1600,11 @@ export namespace SessionPrompt {
|
|
|
1572
1600
|
});
|
|
1573
1601
|
})
|
|
1574
1602
|
.catch((error) => {
|
|
1575
|
-
log.error(
|
|
1603
|
+
log.error(() => ({
|
|
1604
|
+
message: 'failed to generate title',
|
|
1576
1605
|
error,
|
|
1577
1606
|
model: small.info?.id ?? small.modelID,
|
|
1578
|
-
});
|
|
1607
|
+
}));
|
|
1579
1608
|
});
|
|
1580
1609
|
}
|
|
1581
1610
|
}
|
package/src/session/revert.ts
CHANGED
|
@@ -72,7 +72,7 @@ export namespace SessionRevert {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export async function unrevert(input: { sessionID: string }) {
|
|
75
|
-
log.info('unreverting', input);
|
|
75
|
+
log.info(() => ({ message: 'unreverting', ...input }));
|
|
76
76
|
SessionPrompt.assertNotBusy(input.sessionID);
|
|
77
77
|
const session = await Session.get(input.sessionID);
|
|
78
78
|
if (!session.revert) return session;
|
package/src/session/summary.ts
CHANGED
|
@@ -115,7 +115,7 @@ export namespace SessionSummary {
|
|
|
115
115
|
headers: small.info.headers,
|
|
116
116
|
model: small.language,
|
|
117
117
|
});
|
|
118
|
-
log.info('title',
|
|
118
|
+
log.info(() => ({ message: 'title', title: result.text }));
|
|
119
119
|
userMsg.summary.title = result.text;
|
|
120
120
|
await Session.updateMessage(userMsg);
|
|
121
121
|
}
|
|
@@ -152,7 +152,7 @@ export namespace SessionSummary {
|
|
|
152
152
|
if (result) summary = result.text;
|
|
153
153
|
}
|
|
154
154
|
userMsg.summary.body = summary;
|
|
155
|
-
log.info('body',
|
|
155
|
+
log.info(() => ({ message: 'body', body: summary }));
|
|
156
156
|
await Session.updateMessage(userMsg);
|
|
157
157
|
}
|
|
158
158
|
}
|