@link-assistant/agent 0.0.9 → 0.0.12
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/EXAMPLES.md +36 -0
- package/MODELS.md +72 -24
- package/README.md +59 -2
- package/TOOLS.md +20 -0
- package/package.json +35 -2
- package/src/agent/agent.ts +68 -54
- package/src/auth/claude-oauth.ts +426 -0
- package/src/auth/index.ts +28 -26
- package/src/auth/plugins.ts +876 -0
- package/src/bun/index.ts +53 -43
- package/src/bus/global.ts +5 -5
- package/src/bus/index.ts +59 -53
- package/src/cli/bootstrap.js +12 -12
- package/src/cli/bootstrap.ts +6 -6
- package/src/cli/cmd/agent.ts +97 -92
- package/src/cli/cmd/auth.ts +469 -0
- package/src/cli/cmd/cmd.ts +2 -2
- package/src/cli/cmd/export.ts +41 -41
- package/src/cli/cmd/mcp.ts +144 -119
- package/src/cli/cmd/models.ts +30 -29
- package/src/cli/cmd/run.ts +269 -213
- package/src/cli/cmd/stats.ts +185 -146
- package/src/cli/error.ts +17 -13
- package/src/cli/ui.ts +39 -24
- package/src/command/index.ts +26 -26
- package/src/config/config.ts +528 -288
- package/src/config/markdown.ts +15 -15
- package/src/file/ripgrep.ts +201 -169
- package/src/file/time.ts +21 -18
- package/src/file/watcher.ts +51 -42
- package/src/file.ts +1 -1
- package/src/flag/flag.ts +26 -11
- package/src/format/formatter.ts +206 -162
- package/src/format/index.ts +61 -61
- package/src/global/index.ts +21 -21
- package/src/id/id.ts +47 -33
- package/src/index.js +346 -199
- package/src/json-standard/index.ts +67 -51
- package/src/mcp/index.ts +135 -128
- package/src/patch/index.ts +336 -267
- package/src/project/bootstrap.ts +15 -15
- package/src/project/instance.ts +43 -36
- package/src/project/project.ts +47 -47
- package/src/project/state.ts +37 -33
- package/src/provider/models-macro.ts +5 -5
- package/src/provider/models.ts +32 -32
- package/src/provider/opencode.js +19 -19
- package/src/provider/provider.ts +518 -277
- package/src/provider/transform.ts +143 -102
- package/src/server/project.ts +21 -21
- package/src/server/server.ts +111 -105
- package/src/session/agent.js +66 -60
- package/src/session/compaction.ts +136 -111
- package/src/session/index.ts +189 -156
- package/src/session/message-v2.ts +312 -268
- package/src/session/message.ts +73 -57
- package/src/session/processor.ts +180 -166
- package/src/session/prompt.ts +678 -533
- package/src/session/retry.ts +26 -23
- package/src/session/revert.ts +76 -62
- package/src/session/status.ts +26 -26
- package/src/session/summary.ts +97 -76
- package/src/session/system.ts +77 -63
- package/src/session/todo.ts +22 -16
- package/src/snapshot/index.ts +92 -76
- package/src/storage/storage.ts +157 -120
- package/src/tool/bash.ts +116 -106
- package/src/tool/batch.ts +73 -59
- package/src/tool/codesearch.ts +60 -53
- package/src/tool/edit.ts +319 -263
- package/src/tool/glob.ts +32 -28
- package/src/tool/grep.ts +72 -53
- package/src/tool/invalid.ts +7 -7
- package/src/tool/ls.ts +77 -64
- package/src/tool/multiedit.ts +30 -21
- package/src/tool/patch.ts +121 -94
- package/src/tool/read.ts +140 -122
- package/src/tool/registry.ts +38 -38
- package/src/tool/task.ts +93 -60
- package/src/tool/todo.ts +16 -16
- package/src/tool/tool.ts +45 -36
- package/src/tool/webfetch.ts +97 -74
- package/src/tool/websearch.ts +78 -64
- package/src/tool/write.ts +21 -15
- package/src/util/binary.ts +27 -19
- package/src/util/context.ts +8 -8
- package/src/util/defer.ts +7 -5
- package/src/util/error.ts +24 -19
- package/src/util/eventloop.ts +16 -10
- package/src/util/filesystem.ts +37 -33
- package/src/util/fn.ts +11 -8
- package/src/util/iife.ts +1 -1
- package/src/util/keybind.ts +44 -44
- package/src/util/lazy.ts +7 -7
- package/src/util/locale.ts +20 -16
- package/src/util/lock.ts +43 -38
- package/src/util/log.ts +95 -85
- package/src/util/queue.ts +8 -8
- package/src/util/rpc.ts +35 -23
- package/src/util/scrap.ts +4 -4
- package/src/util/signal.ts +5 -5
- package/src/util/timeout.ts +6 -6
- package/src/util/token.ts +2 -2
- package/src/util/wildcard.ts +38 -27
|
@@ -1,191 +1,225 @@
|
|
|
1
|
-
import type { ModelMessage } from
|
|
2
|
-
import { unique } from
|
|
3
|
-
import type { JSONSchema } from
|
|
1
|
+
import type { ModelMessage } from 'ai';
|
|
2
|
+
import { unique } from 'remeda';
|
|
3
|
+
import type { JSONSchema } from 'zod/v4/core';
|
|
4
4
|
|
|
5
5
|
export namespace ProviderTransform {
|
|
6
|
-
function normalizeMessages(
|
|
7
|
-
|
|
6
|
+
function normalizeMessages(
|
|
7
|
+
msgs: ModelMessage[],
|
|
8
|
+
providerID: string,
|
|
9
|
+
modelID: string
|
|
10
|
+
): ModelMessage[] {
|
|
11
|
+
if (modelID.includes('claude')) {
|
|
8
12
|
return msgs.map((msg) => {
|
|
9
|
-
if (
|
|
13
|
+
if (
|
|
14
|
+
(msg.role === 'assistant' || msg.role === 'tool') &&
|
|
15
|
+
Array.isArray(msg.content)
|
|
16
|
+
) {
|
|
10
17
|
msg.content = msg.content.map((part) => {
|
|
11
|
-
if (
|
|
18
|
+
if (
|
|
19
|
+
(part.type === 'tool-call' || part.type === 'tool-result') &&
|
|
20
|
+
'toolCallId' in part
|
|
21
|
+
) {
|
|
12
22
|
return {
|
|
13
23
|
...part,
|
|
14
|
-
toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g,
|
|
15
|
-
}
|
|
24
|
+
toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, '_'),
|
|
25
|
+
};
|
|
16
26
|
}
|
|
17
|
-
return part
|
|
18
|
-
})
|
|
27
|
+
return part;
|
|
28
|
+
});
|
|
19
29
|
}
|
|
20
|
-
return msg
|
|
21
|
-
})
|
|
30
|
+
return msg;
|
|
31
|
+
});
|
|
22
32
|
}
|
|
23
|
-
if (providerID ===
|
|
24
|
-
const result: ModelMessage[] = []
|
|
33
|
+
if (providerID === 'mistral' || modelID.toLowerCase().includes('mistral')) {
|
|
34
|
+
const result: ModelMessage[] = [];
|
|
25
35
|
for (let i = 0; i < msgs.length; i++) {
|
|
26
|
-
const msg = msgs[i]
|
|
27
|
-
const prevMsg = msgs[i - 1]
|
|
28
|
-
const nextMsg = msgs[i + 1]
|
|
36
|
+
const msg = msgs[i];
|
|
37
|
+
const prevMsg = msgs[i - 1];
|
|
38
|
+
const nextMsg = msgs[i + 1];
|
|
29
39
|
|
|
30
|
-
if (
|
|
40
|
+
if (
|
|
41
|
+
(msg.role === 'assistant' || msg.role === 'tool') &&
|
|
42
|
+
Array.isArray(msg.content)
|
|
43
|
+
) {
|
|
31
44
|
msg.content = msg.content.map((part) => {
|
|
32
|
-
if (
|
|
45
|
+
if (
|
|
46
|
+
(part.type === 'tool-call' || part.type === 'tool-result') &&
|
|
47
|
+
'toolCallId' in part
|
|
48
|
+
) {
|
|
33
49
|
// Mistral requires alphanumeric tool call IDs with exactly 9 characters
|
|
34
50
|
const normalizedId = part.toolCallId
|
|
35
|
-
.replace(/[^a-zA-Z0-9]/g,
|
|
51
|
+
.replace(/[^a-zA-Z0-9]/g, '') // Remove non-alphanumeric characters
|
|
36
52
|
.substring(0, 9) // Take first 9 characters
|
|
37
|
-
.padEnd(9,
|
|
53
|
+
.padEnd(9, '0'); // Pad with zeros if less than 9 characters
|
|
38
54
|
|
|
39
55
|
return {
|
|
40
56
|
...part,
|
|
41
57
|
toolCallId: normalizedId,
|
|
42
|
-
}
|
|
58
|
+
};
|
|
43
59
|
}
|
|
44
|
-
return part
|
|
45
|
-
})
|
|
60
|
+
return part;
|
|
61
|
+
});
|
|
46
62
|
}
|
|
47
63
|
|
|
48
|
-
result.push(msg)
|
|
64
|
+
result.push(msg);
|
|
49
65
|
|
|
50
66
|
// Fix message sequence: tool messages cannot be followed by user messages
|
|
51
|
-
if (msg.role ===
|
|
67
|
+
if (msg.role === 'tool' && nextMsg?.role === 'user') {
|
|
52
68
|
result.push({
|
|
53
|
-
role:
|
|
69
|
+
role: 'assistant',
|
|
54
70
|
content: [
|
|
55
71
|
{
|
|
56
|
-
type:
|
|
57
|
-
text:
|
|
72
|
+
type: 'text',
|
|
73
|
+
text: 'Done.',
|
|
58
74
|
},
|
|
59
75
|
],
|
|
60
|
-
})
|
|
76
|
+
});
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
|
-
return result
|
|
79
|
+
return result;
|
|
64
80
|
}
|
|
65
81
|
|
|
66
|
-
return msgs
|
|
82
|
+
return msgs;
|
|
67
83
|
}
|
|
68
84
|
|
|
69
|
-
function applyCaching(
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
function applyCaching(
|
|
86
|
+
msgs: ModelMessage[],
|
|
87
|
+
providerID: string
|
|
88
|
+
): ModelMessage[] {
|
|
89
|
+
const system = msgs.filter((msg) => msg.role === 'system').slice(0, 2);
|
|
90
|
+
const final = msgs.filter((msg) => msg.role !== 'system').slice(-2);
|
|
72
91
|
|
|
73
92
|
const providerOptions = {
|
|
74
93
|
anthropic: {
|
|
75
|
-
cacheControl: { type:
|
|
94
|
+
cacheControl: { type: 'ephemeral' },
|
|
76
95
|
},
|
|
77
96
|
openrouter: {
|
|
78
|
-
cache_control: { type:
|
|
97
|
+
cache_control: { type: 'ephemeral' },
|
|
79
98
|
},
|
|
80
99
|
bedrock: {
|
|
81
|
-
cachePoint: { type:
|
|
100
|
+
cachePoint: { type: 'ephemeral' },
|
|
82
101
|
},
|
|
83
102
|
openaiCompatible: {
|
|
84
|
-
cache_control: { type:
|
|
103
|
+
cache_control: { type: 'ephemeral' },
|
|
85
104
|
},
|
|
86
|
-
}
|
|
105
|
+
};
|
|
87
106
|
|
|
88
107
|
for (const msg of unique([...system, ...final])) {
|
|
89
|
-
const shouldUseContentOptions =
|
|
108
|
+
const shouldUseContentOptions =
|
|
109
|
+
providerID !== 'anthropic' &&
|
|
110
|
+
Array.isArray(msg.content) &&
|
|
111
|
+
msg.content.length > 0;
|
|
90
112
|
|
|
91
113
|
if (shouldUseContentOptions) {
|
|
92
|
-
const lastContent = msg.content[msg.content.length - 1]
|
|
93
|
-
if (lastContent && typeof lastContent ===
|
|
114
|
+
const lastContent = msg.content[msg.content.length - 1];
|
|
115
|
+
if (lastContent && typeof lastContent === 'object') {
|
|
94
116
|
lastContent.providerOptions = {
|
|
95
117
|
...lastContent.providerOptions,
|
|
96
118
|
...providerOptions,
|
|
97
|
-
}
|
|
98
|
-
continue
|
|
119
|
+
};
|
|
120
|
+
continue;
|
|
99
121
|
}
|
|
100
122
|
}
|
|
101
123
|
|
|
102
124
|
msg.providerOptions = {
|
|
103
125
|
...msg.providerOptions,
|
|
104
126
|
...providerOptions,
|
|
105
|
-
}
|
|
127
|
+
};
|
|
106
128
|
}
|
|
107
129
|
|
|
108
|
-
return msgs
|
|
130
|
+
return msgs;
|
|
109
131
|
}
|
|
110
132
|
|
|
111
|
-
export function message(
|
|
112
|
-
msgs
|
|
113
|
-
|
|
114
|
-
|
|
133
|
+
export function message(
|
|
134
|
+
msgs: ModelMessage[],
|
|
135
|
+
providerID: string,
|
|
136
|
+
modelID: string
|
|
137
|
+
) {
|
|
138
|
+
msgs = normalizeMessages(msgs, providerID, modelID);
|
|
139
|
+
if (
|
|
140
|
+
providerID === 'anthropic' ||
|
|
141
|
+
modelID.includes('anthropic') ||
|
|
142
|
+
modelID.includes('claude')
|
|
143
|
+
) {
|
|
144
|
+
msgs = applyCaching(msgs, providerID);
|
|
115
145
|
}
|
|
116
146
|
|
|
117
|
-
return msgs
|
|
147
|
+
return msgs;
|
|
118
148
|
}
|
|
119
149
|
|
|
120
150
|
export function temperature(_providerID: string, modelID: string) {
|
|
121
|
-
if (modelID.toLowerCase().includes(
|
|
122
|
-
if (modelID.toLowerCase().includes(
|
|
123
|
-
if (modelID.toLowerCase().includes(
|
|
124
|
-
return 0
|
|
151
|
+
if (modelID.toLowerCase().includes('qwen')) return 0.55;
|
|
152
|
+
if (modelID.toLowerCase().includes('claude')) return undefined;
|
|
153
|
+
if (modelID.toLowerCase().includes('gemini-3-pro')) return 1.0;
|
|
154
|
+
return 0;
|
|
125
155
|
}
|
|
126
156
|
|
|
127
157
|
export function topP(_providerID: string, modelID: string) {
|
|
128
|
-
if (modelID.toLowerCase().includes(
|
|
129
|
-
return undefined
|
|
158
|
+
if (modelID.toLowerCase().includes('qwen')) return 1;
|
|
159
|
+
return undefined;
|
|
130
160
|
}
|
|
131
161
|
|
|
132
162
|
export function options(
|
|
133
163
|
providerID: string,
|
|
134
164
|
modelID: string,
|
|
135
165
|
npm: string,
|
|
136
|
-
sessionID: string
|
|
166
|
+
sessionID: string
|
|
137
167
|
): Record<string, any> | undefined {
|
|
138
|
-
const result: Record<string, any> = {}
|
|
168
|
+
const result: Record<string, any> = {};
|
|
139
169
|
|
|
140
|
-
if (providerID ===
|
|
141
|
-
result[
|
|
170
|
+
if (providerID === 'openai') {
|
|
171
|
+
result['promptCacheKey'] = sessionID;
|
|
142
172
|
}
|
|
143
173
|
|
|
144
|
-
if (modelID.includes(
|
|
145
|
-
if (modelID.includes(
|
|
146
|
-
result[
|
|
174
|
+
if (modelID.includes('gpt-5') && !modelID.includes('gpt-5-chat')) {
|
|
175
|
+
if (modelID.includes('codex')) {
|
|
176
|
+
result['store'] = false;
|
|
147
177
|
}
|
|
148
178
|
|
|
149
|
-
if (!modelID.includes(
|
|
150
|
-
result[
|
|
179
|
+
if (!modelID.includes('codex') && !modelID.includes('gpt-5-pro')) {
|
|
180
|
+
result['reasoningEffort'] = 'medium';
|
|
151
181
|
}
|
|
152
182
|
|
|
153
|
-
if (modelID.endsWith(
|
|
154
|
-
result[
|
|
183
|
+
if (modelID.endsWith('gpt-5.1') && providerID !== 'azure') {
|
|
184
|
+
result['textVerbosity'] = 'low';
|
|
155
185
|
}
|
|
156
186
|
|
|
157
|
-
if (providerID ===
|
|
158
|
-
result[
|
|
159
|
-
result[
|
|
160
|
-
result[
|
|
187
|
+
if (providerID === 'opencode') {
|
|
188
|
+
result['promptCacheKey'] = sessionID;
|
|
189
|
+
result['include'] = ['reasoning.encrypted_content'];
|
|
190
|
+
result['reasoningSummary'] = 'auto';
|
|
161
191
|
}
|
|
162
192
|
}
|
|
163
|
-
return result
|
|
193
|
+
return result;
|
|
164
194
|
}
|
|
165
195
|
|
|
166
|
-
export function providerOptions(
|
|
196
|
+
export function providerOptions(
|
|
197
|
+
npm: string | undefined,
|
|
198
|
+
providerID: string,
|
|
199
|
+
options: { [x: string]: any }
|
|
200
|
+
) {
|
|
167
201
|
switch (npm) {
|
|
168
|
-
case
|
|
169
|
-
case
|
|
202
|
+
case '@ai-sdk/openai':
|
|
203
|
+
case '@ai-sdk/azure':
|
|
170
204
|
return {
|
|
171
|
-
[
|
|
172
|
-
}
|
|
173
|
-
case
|
|
205
|
+
['openai' as string]: options,
|
|
206
|
+
};
|
|
207
|
+
case '@ai-sdk/amazon-bedrock':
|
|
174
208
|
return {
|
|
175
|
-
[
|
|
176
|
-
}
|
|
177
|
-
case
|
|
209
|
+
['bedrock' as string]: options,
|
|
210
|
+
};
|
|
211
|
+
case '@ai-sdk/anthropic':
|
|
178
212
|
return {
|
|
179
|
-
[
|
|
180
|
-
}
|
|
181
|
-
case
|
|
213
|
+
['anthropic' as string]: options,
|
|
214
|
+
};
|
|
215
|
+
case '@ai-sdk/gateway':
|
|
182
216
|
return {
|
|
183
|
-
[
|
|
184
|
-
}
|
|
217
|
+
['gateway' as string]: options,
|
|
218
|
+
};
|
|
185
219
|
default:
|
|
186
220
|
return {
|
|
187
221
|
[providerID]: options,
|
|
188
|
-
}
|
|
222
|
+
};
|
|
189
223
|
}
|
|
190
224
|
}
|
|
191
225
|
|
|
@@ -193,28 +227,35 @@ export namespace ProviderTransform {
|
|
|
193
227
|
npm: string,
|
|
194
228
|
options: Record<string, any>,
|
|
195
229
|
modelLimit: number,
|
|
196
|
-
globalLimit: number
|
|
230
|
+
globalLimit: number
|
|
197
231
|
): number {
|
|
198
|
-
const modelCap = modelLimit || globalLimit
|
|
199
|
-
const standardLimit = Math.min(modelCap, globalLimit)
|
|
232
|
+
const modelCap = modelLimit || globalLimit;
|
|
233
|
+
const standardLimit = Math.min(modelCap, globalLimit);
|
|
200
234
|
|
|
201
|
-
if (npm ===
|
|
202
|
-
const thinking = options?.[
|
|
203
|
-
const budgetTokens =
|
|
204
|
-
|
|
235
|
+
if (npm === '@ai-sdk/anthropic') {
|
|
236
|
+
const thinking = options?.['thinking'];
|
|
237
|
+
const budgetTokens =
|
|
238
|
+
typeof thinking?.['budgetTokens'] === 'number'
|
|
239
|
+
? thinking['budgetTokens']
|
|
240
|
+
: 0;
|
|
241
|
+
const enabled = thinking?.['type'] === 'enabled';
|
|
205
242
|
if (enabled && budgetTokens > 0) {
|
|
206
243
|
// Return text tokens so that text + thinking <= model cap, preferring 32k text when possible.
|
|
207
244
|
if (budgetTokens + standardLimit <= modelCap) {
|
|
208
|
-
return standardLimit
|
|
245
|
+
return standardLimit;
|
|
209
246
|
}
|
|
210
|
-
return modelCap - budgetTokens
|
|
247
|
+
return modelCap - budgetTokens;
|
|
211
248
|
}
|
|
212
249
|
}
|
|
213
250
|
|
|
214
|
-
return standardLimit
|
|
251
|
+
return standardLimit;
|
|
215
252
|
}
|
|
216
253
|
|
|
217
|
-
export function schema(
|
|
254
|
+
export function schema(
|
|
255
|
+
_providerID: string,
|
|
256
|
+
_modelID: string,
|
|
257
|
+
schema: JSONSchema.BaseSchema
|
|
258
|
+
) {
|
|
218
259
|
/*
|
|
219
260
|
if (["openai", "azure"].includes(providerID)) {
|
|
220
261
|
if (schema.type === "object" && schema.properties) {
|
|
@@ -236,6 +277,6 @@ export namespace ProviderTransform {
|
|
|
236
277
|
}
|
|
237
278
|
*/
|
|
238
279
|
|
|
239
|
-
return schema
|
|
280
|
+
return schema;
|
|
240
281
|
}
|
|
241
282
|
}
|
package/src/server/project.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { Hono } from
|
|
2
|
-
import { describeRoute } from
|
|
3
|
-
import { resolver } from
|
|
4
|
-
import { Instance } from
|
|
5
|
-
import { Project } from
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { describeRoute } from 'hono-openapi';
|
|
3
|
+
import { resolver } from 'hono-openapi';
|
|
4
|
+
import { Instance } from '../project/instance';
|
|
5
|
+
import { Project } from '../project/project';
|
|
6
6
|
|
|
7
7
|
export const ProjectRoute = new Hono()
|
|
8
8
|
.get(
|
|
9
|
-
|
|
9
|
+
'/',
|
|
10
10
|
describeRoute({
|
|
11
|
-
description:
|
|
12
|
-
operationId:
|
|
11
|
+
description: 'List all projects',
|
|
12
|
+
operationId: 'project.list',
|
|
13
13
|
responses: {
|
|
14
14
|
200: {
|
|
15
|
-
description:
|
|
15
|
+
description: 'List of projects',
|
|
16
16
|
content: {
|
|
17
|
-
|
|
17
|
+
'application/json': {
|
|
18
18
|
schema: resolver(Project.Info.array()),
|
|
19
19
|
},
|
|
20
20
|
},
|
|
@@ -22,20 +22,20 @@ export const ProjectRoute = new Hono()
|
|
|
22
22
|
},
|
|
23
23
|
}),
|
|
24
24
|
async (c) => {
|
|
25
|
-
const projects = await Project.list()
|
|
26
|
-
return c.json(projects)
|
|
27
|
-
}
|
|
25
|
+
const projects = await Project.list();
|
|
26
|
+
return c.json(projects);
|
|
27
|
+
}
|
|
28
28
|
)
|
|
29
29
|
.get(
|
|
30
|
-
|
|
30
|
+
'/current',
|
|
31
31
|
describeRoute({
|
|
32
|
-
description:
|
|
33
|
-
operationId:
|
|
32
|
+
description: 'Get the current project',
|
|
33
|
+
operationId: 'project.current',
|
|
34
34
|
responses: {
|
|
35
35
|
200: {
|
|
36
|
-
description:
|
|
36
|
+
description: 'Current project',
|
|
37
37
|
content: {
|
|
38
|
-
|
|
38
|
+
'application/json': {
|
|
39
39
|
schema: resolver(Project.Info),
|
|
40
40
|
},
|
|
41
41
|
},
|
|
@@ -43,6 +43,6 @@ export const ProjectRoute = new Hono()
|
|
|
43
43
|
},
|
|
44
44
|
}),
|
|
45
45
|
async (c) => {
|
|
46
|
-
return c.json(Instance.project)
|
|
47
|
-
}
|
|
48
|
-
)
|
|
46
|
+
return c.json(Instance.project);
|
|
47
|
+
}
|
|
48
|
+
);
|