@amalgm/chat 0.2.8 → 0.2.9-main.34746990150
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/PURPOSE.md +94 -41
- package/README.md +17 -4
- package/dist/acp/projection.d.ts +8 -0
- package/dist/acp/projection.d.ts.map +1 -1
- package/dist/acp/projection.js +10 -3
- package/dist/acp/projection.js.map +1 -1
- package/dist/conversations/index.d.ts +1 -0
- package/dist/conversations/index.d.ts.map +1 -1
- package/dist/conversations/index.js +1 -0
- package/dist/conversations/index.js.map +1 -1
- package/dist/conversations/transcript-parts.d.ts +38 -0
- package/dist/conversations/transcript-parts.d.ts.map +1 -0
- package/dist/conversations/transcript-parts.js +2 -0
- package/dist/conversations/transcript-parts.js.map +1 -0
- package/dist/conversations/transcript-tools.d.ts +11 -0
- package/dist/conversations/transcript-tools.d.ts.map +1 -0
- package/dist/conversations/transcript-tools.js +47 -0
- package/dist/conversations/transcript-tools.js.map +1 -0
- package/dist/conversations/transcript.d.ts +5 -4
- package/dist/conversations/transcript.d.ts.map +1 -1
- package/dist/conversations/transcript.js +43 -143
- package/dist/conversations/transcript.js.map +1 -1
- package/dist/conversations/types.d.ts +19 -0
- package/dist/conversations/types.d.ts.map +1 -1
- package/dist/conversations/types.js.map +1 -1
- package/dist/events/constructors.d.ts.map +1 -1
- package/dist/events/constructors.js +2 -52
- package/dist/events/constructors.js.map +1 -1
- package/dist/events/schema.d.ts +72 -72
- package/dist/events/schema.js +16 -16
- package/dist/events/schema.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/input/prompt.js +1 -1
- package/dist/input/prompt.js.map +1 -1
- package/dist/mcp/server.js +13 -13
- package/dist/mcp/server.js.map +1 -1
- package/dist/normalizers/claude.d.ts +142 -142
- package/dist/normalizers/claude.d.ts.map +1 -1
- package/dist/normalizers/claude.js +23 -37
- package/dist/normalizers/claude.js.map +1 -1
- package/dist/normalizers/codex.d.ts +71 -71
- package/dist/normalizers/codex.d.ts.map +1 -1
- package/dist/normalizers/codex.js +12 -24
- package/dist/normalizers/codex.js.map +1 -1
- package/dist/normalizers/index.d.ts +0 -1
- package/dist/normalizers/index.d.ts.map +1 -1
- package/dist/normalizers/index.js +0 -1
- package/dist/normalizers/index.js.map +1 -1
- package/dist/normalizers/opencode.d.ts.map +1 -1
- package/dist/normalizers/opencode.js +9 -6
- package/dist/normalizers/opencode.js.map +1 -1
- package/dist/normalizers/pi.d.ts.map +1 -1
- package/dist/normalizers/pi.js +27 -14
- package/dist/normalizers/pi.js.map +1 -1
- package/dist/sessions/chat.d.ts +5 -5
- package/dist/sessions/chat.d.ts.map +1 -1
- package/dist/sessions/chat.js +51 -19
- package/dist/sessions/chat.js.map +1 -1
- package/dist/sessions/index.d.ts +1 -1
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +1 -1
- package/dist/sessions/index.js.map +1 -1
- package/dist/usage/acp.d.ts +4 -0
- package/dist/usage/acp.d.ts.map +1 -0
- package/dist/usage/acp.js +20 -0
- package/dist/usage/acp.js.map +1 -0
- package/dist/usage/finalize.d.ts +1 -11
- package/dist/usage/finalize.d.ts.map +1 -1
- package/dist/usage/finalize.js +29 -47
- package/dist/usage/finalize.js.map +1 -1
- package/dist/usage/index.d.ts +2 -1
- package/dist/usage/index.d.ts.map +1 -1
- package/dist/usage/index.js +2 -1
- package/dist/usage/index.js.map +1 -1
- package/dist/usage/normalize.d.ts +8 -9
- package/dist/usage/normalize.d.ts.map +1 -1
- package/dist/usage/normalize.js +20 -20
- package/dist/usage/normalize.js.map +1 -1
- package/dist/usage/ports.d.ts +4 -4
- package/dist/usage/ports.d.ts.map +1 -1
- package/dist/usage/ports.js +5 -5
- package/dist/usage/ports.js.map +1 -1
- package/dist/usage/tokens.d.ts +13 -38
- package/dist/usage/tokens.d.ts.map +1 -1
- package/dist/usage/tokens.js +39 -72
- package/dist/usage/tokens.js.map +1 -1
- package/host/adapters/acp-prompt.js +36 -0
- package/host/adapters/acp.js +50 -71
- package/host/adapters/attachments.js +37 -0
- package/host/adapters/claude.js +9 -2
- package/host/adapters/codex.js +36 -18
- package/host/adapters/cursor.js +72 -99
- package/host/adapters/opencode.js +39 -25
- package/host/adapters/pi.js +24 -19
- package/host/adapters/prompt.js +13 -21
- package/host/adapters/provider-url.js +8 -0
- package/host/auth.js +10 -9
- package/host/http.js +3 -2
- package/host/model-resolution.js +7 -0
- package/host/native-contract.js +4 -3
- package/host/native-runtime.js +25 -11
- package/host/sqlite/index.d.ts +2 -0
- package/host/sqlite/index.js +48 -4
- package/host/tooling/runtime-home.js +1 -1
- package/host/tooling/system-instructions.js +7 -6
- package/host/tooling/system-prompt.js +12 -18
- package/package.json +26 -2
- package/dist/normalizers/cursor.d.ts +0 -33
- package/dist/normalizers/cursor.d.ts.map +0 -1
- package/dist/normalizers/cursor.js +0 -196
- package/dist/normalizers/cursor.js.map +0 -1
package/host/native-runtime.js
CHANGED
|
@@ -6,6 +6,7 @@ import { OpenCodeAdapter } from './adapters/opencode.js';
|
|
|
6
6
|
import { PiAdapter } from './adapters/pi.js';
|
|
7
7
|
import { AcpAdapter } from './adapters/acp.js';
|
|
8
8
|
import { assertExecutionInput } from './adapters/input-capabilities.js';
|
|
9
|
+
import { materializePromptAttachments } from './adapters/attachments.js';
|
|
9
10
|
import { NativeExecutionPreparer } from './native-contract.js';
|
|
10
11
|
import { forwardPlatformEgress } from './platform-egress.js';
|
|
11
12
|
import { generateConversationTitle } from './title-generator.js';
|
|
@@ -78,6 +79,8 @@ export class NativeChatRuntime {
|
|
|
78
79
|
this.sessions.set(sessionId, session);
|
|
79
80
|
try {
|
|
80
81
|
session.native = await execution.binding.adapter.create(contract);
|
|
82
|
+
session.recoveryHistory = providerSessionId && session.native?.providerSessionId === providerSessionId
|
|
83
|
+
? null : messages;
|
|
81
84
|
} catch (error) {
|
|
82
85
|
this.sessions.delete(sessionId);
|
|
83
86
|
throw error;
|
|
@@ -99,10 +102,12 @@ export class NativeChatRuntime {
|
|
|
99
102
|
null,
|
|
100
103
|
);
|
|
101
104
|
const adapter = request.execution.binding.adapter;
|
|
105
|
+
const native = await adapter.create(contract);
|
|
102
106
|
state.adapter = adapter;
|
|
103
107
|
state.contract = contract;
|
|
104
108
|
state.executionRevision = request.execution.revision;
|
|
105
|
-
state.native =
|
|
109
|
+
state.native = native;
|
|
110
|
+
state.recoveryHistory = request.previousMessages;
|
|
106
111
|
}
|
|
107
112
|
|
|
108
113
|
const contract = this.preparer.forSession(
|
|
@@ -112,16 +117,27 @@ export class NativeChatRuntime {
|
|
|
112
117
|
state.native?.providerSessionId || state.contract.providerSessionId,
|
|
113
118
|
);
|
|
114
119
|
state.contract = contract;
|
|
115
|
-
const
|
|
120
|
+
const input = state.recoveryHistory
|
|
116
121
|
? promptWithRecoveryHistory(state.recoveryHistory, request.prompt)
|
|
117
122
|
: request.prompt;
|
|
123
|
+
const materialize = state.adapter.materializeAttachments ?? state.adapter.outputType !== 'acp';
|
|
124
|
+
const prompt = materialize ? await materializePromptAttachments(input, this.preparer.runtimeHomeRoot) : input;
|
|
118
125
|
state.recoveryHistory = null;
|
|
119
126
|
let sequence = 0;
|
|
120
|
-
for await (const event of state.adapter.prompt(state.native, prompt, contract)) {
|
|
127
|
+
for await (const event of state.adapter.prompt(state.native, prompt, contract, { recordUsage: request.recordUsage })) {
|
|
121
128
|
if (state.adapter.outputType === 'acp') {
|
|
122
129
|
yield event;
|
|
123
130
|
continue;
|
|
124
131
|
}
|
|
132
|
+
if (event.type === 'error' || (event.type === 'done' && event.stopReason === 'error')) {
|
|
133
|
+
throw Object.assign(new Error(event.message || 'The provider turn failed'), {
|
|
134
|
+
code: 'PROVIDER_TURN_FAILED',
|
|
135
|
+
cause: event.raw,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (event.type === 'usage.final') {
|
|
139
|
+
await request.recordUsage?.({ usage: event.usage, raw: event.raw ?? null });
|
|
140
|
+
}
|
|
125
141
|
const update = toAcpSessionUpdate(event, {
|
|
126
142
|
conversationId: request.sessionId,
|
|
127
143
|
turnId: request.turnId,
|
|
@@ -186,16 +202,14 @@ export class NativeChatRuntime {
|
|
|
186
202
|
}
|
|
187
203
|
|
|
188
204
|
function promptWithRecoveryHistory(messages, prompt) {
|
|
189
|
-
|
|
190
|
-
for (const message of messages.slice(-40)) {
|
|
191
|
-
const label = message.role === 'user' ? 'Human' : 'Assistant';
|
|
192
|
-
const text = typeof message.contentPlain === 'string' ? message.contentPlain.trim() : '';
|
|
193
|
-
if (text) lines.push(`${label}: ${text}`);
|
|
194
|
-
}
|
|
195
|
-
if (lines.length === 0) return prompt;
|
|
205
|
+
if (messages.length === 0) return prompt;
|
|
196
206
|
return {
|
|
197
207
|
parts: [
|
|
198
|
-
{ type: '
|
|
208
|
+
{ type: 'resource', resource: {
|
|
209
|
+
uri: 'amalgm:conversation-history',
|
|
210
|
+
mimeType: 'application/json',
|
|
211
|
+
text: JSON.stringify(messages.map(({ role, parts, contentPlain, error }) => ({ role, parts, contentPlain, error }))),
|
|
212
|
+
} },
|
|
199
213
|
...prompt.parts,
|
|
200
214
|
],
|
|
201
215
|
};
|
package/host/sqlite/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type Database from 'better-sqlite3';
|
|
2
2
|
import type {
|
|
3
3
|
AppendTurnUpdateInput,
|
|
4
|
+
AppendTurnUsageInput,
|
|
4
5
|
AppendTurnUpdatesInput,
|
|
5
6
|
BeginConversationTurnInput,
|
|
6
7
|
ConversationMessage,
|
|
@@ -56,6 +57,7 @@ export class SqliteConversationStore implements ConversationStorePort {
|
|
|
56
57
|
}, updatedAt: string): ConversationRecord;
|
|
57
58
|
archiveConversation(scope: ConversationScope, conversationId: string, archivedAt: string): Promise<ConversationRecord>;
|
|
58
59
|
beginTurn(input: BeginConversationTurnInput): Promise<ConversationTurn>;
|
|
60
|
+
appendTurnUsage(input: AppendTurnUsageInput): Promise<void>;
|
|
59
61
|
appendTurnUpdate(input: AppendTurnUpdateInput): Promise<StoredTurnUpdate>;
|
|
60
62
|
appendTurnUpdates(input: AppendTurnUpdatesInput): Promise<readonly StoredTurnUpdate[]>;
|
|
61
63
|
sealTurn(input: SealConversationTurnInput): Promise<ConversationTurn>;
|
package/host/sqlite/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import Database from 'better-sqlite3';
|
|
4
|
+
import { finalizeTurnUsage, normalizeUsage } from '../../dist/usage/index.js';
|
|
4
5
|
import {
|
|
5
6
|
applyAcpTranscriptUpdate,
|
|
6
7
|
createAcpTranscriptState,
|
|
@@ -8,7 +9,7 @@ import {
|
|
|
8
9
|
promptContentPlain,
|
|
9
10
|
} from '../../dist/conversations/index.js';
|
|
10
11
|
|
|
11
|
-
const SCHEMA_VERSION =
|
|
12
|
+
const SCHEMA_VERSION = 3;
|
|
12
13
|
const TERMINAL = new Set(['completed', 'failed', 'cancelled', 'interrupted']);
|
|
13
14
|
|
|
14
15
|
export class SqliteConversationStoreError extends Error {
|
|
@@ -77,12 +78,22 @@ function conversationFromRow(row) {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
function turnFromRow(row) {
|
|
81
|
+
const execution = Object.freeze(parseJson(row.execution_json, {}));
|
|
82
|
+
const observations = Object.freeze(parseJson(row.usage_json, []));
|
|
83
|
+
const records = observations.map(record => record.usage);
|
|
84
|
+
const usage = finalizeTurnUsage({
|
|
85
|
+
contract: { harness: execution.agent?.adapterId },
|
|
86
|
+
usage: records.at(-1), usageRecords: records,
|
|
87
|
+
});
|
|
80
88
|
return Object.freeze({
|
|
89
|
+
contextUsage: parseJson(row.context_usage_json, null),
|
|
90
|
+
usage: usage ? Object.freeze(usage) : null,
|
|
91
|
+
usageRecords: observations,
|
|
81
92
|
id: row.id,
|
|
82
93
|
conversationId: row.conversation_id,
|
|
83
94
|
status: row.status,
|
|
84
95
|
prompt: Object.freeze(parseJson(row.prompt_json, { parts: [] })),
|
|
85
|
-
execution
|
|
96
|
+
execution,
|
|
86
97
|
error: row.error_json ? Object.freeze(parseJson(row.error_json, {})) : null,
|
|
87
98
|
createdAt: row.created_at,
|
|
88
99
|
startedAt: row.started_at,
|
|
@@ -110,6 +121,7 @@ function messageFromRow(row) {
|
|
|
110
121
|
parts: Object.freeze(parseJson(row.parts_json, [])),
|
|
111
122
|
contentPlain: row.content_plain,
|
|
112
123
|
modelId: row.model_id,
|
|
124
|
+
error: row.role === 'assistant' && row.error_json ? Object.freeze(parseJson(row.error_json, {})) : null,
|
|
113
125
|
createdAt: row.created_at,
|
|
114
126
|
updatedAt: row.updated_at,
|
|
115
127
|
});
|
|
@@ -134,6 +146,18 @@ function migrate(database) {
|
|
|
134
146
|
);
|
|
135
147
|
}
|
|
136
148
|
if (version === SCHEMA_VERSION) return;
|
|
149
|
+
if (version === 2) {
|
|
150
|
+
database.exec(`
|
|
151
|
+
BEGIN IMMEDIATE;
|
|
152
|
+
ALTER TABLE turns ADD COLUMN usage_json TEXT NOT NULL DEFAULT '[]';
|
|
153
|
+
ALTER TABLE turns ADD COLUMN context_usage_json TEXT;
|
|
154
|
+
INSERT INTO schema_migrations(version, applied_at)
|
|
155
|
+
VALUES (3, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
|
156
|
+
PRAGMA user_version = 3;
|
|
157
|
+
COMMIT;
|
|
158
|
+
`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
137
161
|
if (version === 1) {
|
|
138
162
|
database.exec(`
|
|
139
163
|
BEGIN IMMEDIATE;
|
|
@@ -144,6 +168,7 @@ function migrate(database) {
|
|
|
144
168
|
PRAGMA user_version = 2;
|
|
145
169
|
COMMIT;
|
|
146
170
|
`);
|
|
171
|
+
migrate(database);
|
|
147
172
|
return;
|
|
148
173
|
}
|
|
149
174
|
database.exec(`
|
|
@@ -181,6 +206,8 @@ function migrate(database) {
|
|
|
181
206
|
prompt_json TEXT NOT NULL,
|
|
182
207
|
execution_json TEXT NOT NULL,
|
|
183
208
|
error_json TEXT,
|
|
209
|
+
usage_json TEXT NOT NULL DEFAULT '[]',
|
|
210
|
+
context_usage_json TEXT,
|
|
184
211
|
created_at TEXT NOT NULL,
|
|
185
212
|
started_at TEXT NOT NULL,
|
|
186
213
|
completed_at TEXT,
|
|
@@ -237,7 +264,9 @@ function migrate(database) {
|
|
|
237
264
|
VALUES (1, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
|
238
265
|
INSERT INTO schema_migrations(version, applied_at)
|
|
239
266
|
VALUES (2, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
|
240
|
-
|
|
267
|
+
INSERT INTO schema_migrations(version, applied_at)
|
|
268
|
+
VALUES (3, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
|
269
|
+
PRAGMA user_version = 3;
|
|
241
270
|
COMMIT;
|
|
242
271
|
`);
|
|
243
272
|
}
|
|
@@ -506,6 +535,18 @@ export class SqliteConversationStore {
|
|
|
506
535
|
}
|
|
507
536
|
}
|
|
508
537
|
|
|
538
|
+
async appendTurnUsage(input) {
|
|
539
|
+
this.database.transaction(() => {
|
|
540
|
+
const turn = this.#requireTurn(input, input.turnId);
|
|
541
|
+
if (turn.conversation_id !== input.conversationId || turn.status !== 'running') {
|
|
542
|
+
throw new SqliteConversationStoreError('TURN_NOT_RUNNING', `Turn is not running: ${input.turnId}`);
|
|
543
|
+
}
|
|
544
|
+
const records = parseJson(turn.usage_json, []);
|
|
545
|
+
records.push({ usage: normalizeUsage(input.observation.usage), raw: input.observation.raw ?? null });
|
|
546
|
+
this.database.prepare('UPDATE turns SET usage_json = ? WHERE id = ?').run(stringify(records), turn.id);
|
|
547
|
+
})();
|
|
548
|
+
}
|
|
549
|
+
|
|
509
550
|
async appendTurnUpdate(input) {
|
|
510
551
|
const updates = await this.appendTurnUpdates({
|
|
511
552
|
...input,
|
|
@@ -543,6 +584,8 @@ export class SqliteConversationStore {
|
|
|
543
584
|
sequence += 1;
|
|
544
585
|
}
|
|
545
586
|
this.database.prepare('UPDATE turns SET next_sequence = ? WHERE id = ?').run(sequence, turn.id);
|
|
587
|
+
const context = input.updates.findLast(item => item.update.sessionUpdate === 'usage_update');
|
|
588
|
+
if (context) this.database.prepare('UPDATE turns SET context_usage_json = ? WHERE id = ?').run(stringify(context.update), turn.id);
|
|
546
589
|
return stored;
|
|
547
590
|
});
|
|
548
591
|
return transaction().map(updateFromRow);
|
|
@@ -641,7 +684,8 @@ export class SqliteConversationStore {
|
|
|
641
684
|
async listMessages(scope, conversationId) {
|
|
642
685
|
const conversation = this.#requireConversation(scope, conversationId);
|
|
643
686
|
return this.database.prepare(`
|
|
644
|
-
SELECT
|
|
687
|
+
SELECT m.*, t.error_json FROM messages m JOIN turns t ON t.id = m.turn_id
|
|
688
|
+
WHERE m.conversation_id = ? ORDER BY m.created_at ASC, m.role DESC
|
|
645
689
|
`).all(conversation.id).map(messageFromRow);
|
|
646
690
|
}
|
|
647
691
|
|
|
@@ -38,8 +38,8 @@ function cappedDocContent(content, maxChars = CONTEXT_FILE_MAX_CHARS) {
|
|
|
38
38
|
return `${text.slice(0, maxChars).trimEnd()}\n[truncated]`;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export function systemInstructionsPath() {
|
|
42
|
-
return systemContextPaths(
|
|
41
|
+
export function systemInstructionsPath(dir = amalgmDir()) {
|
|
42
|
+
return systemContextPaths(dir).instructions;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function escapeAttribute(value) {
|
|
@@ -50,13 +50,14 @@ function escapeAttribute(value) {
|
|
|
50
50
|
.replace(/>/g, '>');
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function systemInstructionsBlock() {
|
|
54
|
-
const filePath = systemInstructionsPath();
|
|
53
|
+
export function systemInstructionsBlock(dir) {
|
|
54
|
+
const filePath = systemInstructionsPath(dir);
|
|
55
55
|
let content = '';
|
|
56
56
|
try {
|
|
57
57
|
content = fs.readFileSync(filePath, 'utf8');
|
|
58
|
-
} catch {
|
|
59
|
-
return '';
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error.code === 'ENOENT') return '';
|
|
60
|
+
throw error;
|
|
60
61
|
}
|
|
61
62
|
if (isEmptyContextDoc(content)) return '';
|
|
62
63
|
return [
|
|
@@ -4,27 +4,12 @@ function trimBlock(value) {
|
|
|
4
4
|
return String(value || '').trim();
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
function safeBlock(label, render) {
|
|
8
|
-
if (typeof render !== 'function') return '';
|
|
9
|
-
try {
|
|
10
|
-
return trimBlock(render());
|
|
11
|
-
} catch (error) {
|
|
12
|
-
const message = error instanceof Error ? error.message.split('\n')[0] : String(error);
|
|
13
|
-
console.warn(`[chat] ${label} failed:`, message);
|
|
14
|
-
return '';
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
7
|
/** Compose machine, project, and exact agent-revision instructions at preparation. */
|
|
19
8
|
export function composeSystemPrompt(contract, options = {}) {
|
|
20
9
|
const parts = [];
|
|
21
|
-
const systemInstructions =
|
|
22
|
-
const projectContext =
|
|
23
|
-
|
|
24
|
-
typeof options.projectContextPromptBlock === 'function'
|
|
25
|
-
? () => options.projectContextPromptBlock(contract)
|
|
26
|
-
: null,
|
|
27
|
-
);
|
|
10
|
+
const systemInstructions = systemInstructionsBlock(options.amalgmDir);
|
|
11
|
+
const projectContext = typeof options.projectContextPromptBlock === 'function'
|
|
12
|
+
? trimBlock(options.projectContextPromptBlock(contract)) : '';
|
|
28
13
|
const agentInstructions = trimBlock(contract?.compiledAgentInstructions);
|
|
29
14
|
if (systemInstructions) parts.push(systemInstructions);
|
|
30
15
|
if (projectContext) parts.push(projectContext);
|
|
@@ -36,3 +21,12 @@ export function composeSystemPrompt(contract, options = {}) {
|
|
|
36
21
|
export function preparedSystemPrompt(contract) {
|
|
37
22
|
return trimBlock(contract?.instructions?.text);
|
|
38
23
|
}
|
|
24
|
+
|
|
25
|
+
/** Describe the exact regular-tool projection supplied by the composing host. */
|
|
26
|
+
export function toolSystemInstructions(servers) {
|
|
27
|
+
const tools = servers.flatMap((server) => {
|
|
28
|
+
const selected = server._meta?.['amalgm.dev/tools'];
|
|
29
|
+
return Array.isArray(selected) ? selected.map((tool) => ({ server: server.name, ...tool })) : [];
|
|
30
|
+
});
|
|
31
|
+
return tools.length ? `Selected tools (call through their MCP server):\n${JSON.stringify(tools)}` : '';
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amalgm/chat",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9-main.34746990150",
|
|
4
4
|
"description": "A provider-agnostic agent chat SDK with ACP content, prepared execution, normalized streams, and usage.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -86,7 +86,12 @@
|
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.json",
|
|
89
|
-
"test": "npm run build && node --test"
|
|
89
|
+
"test": "npm run build && node --test",
|
|
90
|
+
"release:admit": "node scripts/release/package.mjs admit",
|
|
91
|
+
"release:prepare": "node scripts/release/package.mjs prepare",
|
|
92
|
+
"release:examine": "node scripts/release/package.mjs examine",
|
|
93
|
+
"release:publish": "node scripts/release/package.mjs publish",
|
|
94
|
+
"test:release": "node --test scripts/release/*.test.mjs"
|
|
90
95
|
},
|
|
91
96
|
"dependencies": {
|
|
92
97
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
@@ -100,5 +105,24 @@
|
|
|
100
105
|
"devDependencies": {
|
|
101
106
|
"@types/better-sqlite3": "^7.6.13",
|
|
102
107
|
"typescript": "^5.7.3"
|
|
108
|
+
},
|
|
109
|
+
"amalgmRelease": {
|
|
110
|
+
"schema": 1,
|
|
111
|
+
"workflow": "verify.yml",
|
|
112
|
+
"jobs": [
|
|
113
|
+
"verify"
|
|
114
|
+
],
|
|
115
|
+
"verify": "test",
|
|
116
|
+
"cli": []
|
|
117
|
+
},
|
|
118
|
+
"allowScripts": {
|
|
119
|
+
"better-sqlite3@12.11.1": true
|
|
120
|
+
},
|
|
121
|
+
"gitHead": "d2d09289c5a18d926cf7c4d2f083d32760003d2d",
|
|
122
|
+
"amalgmSource": {
|
|
123
|
+
"repository": "amalgm-inc/amalgm-chat",
|
|
124
|
+
"branch": "main",
|
|
125
|
+
"commit": "d2d09289c5a18d926cf7c4d2f083d32760003d2d",
|
|
126
|
+
"occurrence": "34746990150"
|
|
103
127
|
}
|
|
104
128
|
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cursor ACP normalizer. `cursorStopReason` is pure and exported at
|
|
3
|
-
* module level; `normalizeCursorUpdate` / `cursorPromptUsage` construct
|
|
4
|
-
* events, so they live behind `createCursorNormalizer(events)`.
|
|
5
|
-
*
|
|
6
|
-
* Because amalgm's event vocabulary already mirrors ACP `session/update`,
|
|
7
|
-
* this is a thin shim, not a per-event translation table.
|
|
8
|
-
*/
|
|
9
|
-
import type { AmalgmEvent, EventConstructors } from '../events/index.js';
|
|
10
|
-
/** Engine cursor.js:27-35. ACP PromptResponse stopReason -> amalgm done stopReason. */
|
|
11
|
-
export declare function cursorStopReason(stopReason: unknown): string;
|
|
12
|
-
/** Per-tool bookkeeping row (engine `state.tools` Map values). */
|
|
13
|
-
export interface CursorToolRecord {
|
|
14
|
-
toolName: any;
|
|
15
|
-
kind: any;
|
|
16
|
-
input: any;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Per-prompt normalizer state — created by the adapter per prompt, carries
|
|
20
|
-
* `providerSessionId` and the tool-call bookkeeping map (engine contract).
|
|
21
|
-
*/
|
|
22
|
-
export interface CursorNormalizerState {
|
|
23
|
-
providerSessionId?: string | null | undefined;
|
|
24
|
-
tools: Map<string, CursorToolRecord>;
|
|
25
|
-
}
|
|
26
|
-
/** The engine `normalizers/cursor.js` event-constructing export set. */
|
|
27
|
-
export interface CursorNormalizer {
|
|
28
|
-
normalizeCursorUpdate: (update: unknown, state: CursorNormalizerState) => AmalgmEvent[];
|
|
29
|
-
cursorPromptUsage: (usage: unknown, base?: Record<string, unknown>) => AmalgmEvent | null;
|
|
30
|
-
}
|
|
31
|
-
/** Build the Cursor normalizer over injected event constructors. */
|
|
32
|
-
export declare function createCursorNormalizer(events: EventConstructors): CursorNormalizer;
|
|
33
|
-
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/normalizers/cursor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAkBzE,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAO5D;AA8CD,kEAAkE;AAClE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,GAAG,CAAC;IACd,IAAI,EAAE,GAAG,CAAC;IACV,KAAK,EAAE,GAAG,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACtC;AAcD,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB,KAAK,WAAW,EAAE,CAAC;IACxF,iBAAiB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,WAAW,GAAG,IAAI,CAAC;CAC3F;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,GAAG,gBAAgB,CAwGlF"}
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cursor ACP normalizer. `cursorStopReason` is pure and exported at
|
|
3
|
-
* module level; `normalizeCursorUpdate` / `cursorPromptUsage` construct
|
|
4
|
-
* events, so they live behind `createCursorNormalizer(events)`.
|
|
5
|
-
*
|
|
6
|
-
* Because amalgm's event vocabulary already mirrors ACP `session/update`,
|
|
7
|
-
* this is a thin shim, not a per-event translation table.
|
|
8
|
-
*/
|
|
9
|
-
/** ACP tool kinds → Amalgm tool kinds. */
|
|
10
|
-
const ACP_TOOL_KINDS = {
|
|
11
|
-
read: 'file_read',
|
|
12
|
-
edit: 'file_edit',
|
|
13
|
-
delete: 'file_edit',
|
|
14
|
-
move: 'file_write',
|
|
15
|
-
search: 'search',
|
|
16
|
-
execute: 'bash',
|
|
17
|
-
fetch: 'browser',
|
|
18
|
-
think: 'unknown',
|
|
19
|
-
switch_mode: 'unknown',
|
|
20
|
-
other: 'unknown',
|
|
21
|
-
};
|
|
22
|
-
/** Engine cursor.js:27-35. ACP PromptResponse stopReason -> amalgm done stopReason. */
|
|
23
|
-
export function cursorStopReason(stopReason) {
|
|
24
|
-
const clean = String(stopReason || '').trim();
|
|
25
|
-
if (!clean || clean === 'end_turn')
|
|
26
|
-
return 'end_turn';
|
|
27
|
-
if (clean === 'cancelled')
|
|
28
|
-
return 'cancelled';
|
|
29
|
-
if (clean === 'refusal')
|
|
30
|
-
return 'refusal';
|
|
31
|
-
if (clean === 'max_tokens' || clean === 'max_turn_requests')
|
|
32
|
-
return clean;
|
|
33
|
-
return 'end_turn';
|
|
34
|
-
}
|
|
35
|
-
/** Engine cursor.js:37-41. */
|
|
36
|
-
function contentText(content) {
|
|
37
|
-
if (!content || typeof content !== 'object')
|
|
38
|
-
return '';
|
|
39
|
-
if (typeof content['text'] === 'string')
|
|
40
|
-
return content['text'];
|
|
41
|
-
return '';
|
|
42
|
-
}
|
|
43
|
-
/** Engine cursor.js:43-63. ACP ToolCallContent[] -> a renderable output value. */
|
|
44
|
-
function toolOutput(content) {
|
|
45
|
-
if (!Array.isArray(content) || content.length === 0)
|
|
46
|
-
return undefined;
|
|
47
|
-
const texts = [];
|
|
48
|
-
const diffs = [];
|
|
49
|
-
for (const item of content) {
|
|
50
|
-
if (!item || typeof item !== 'object')
|
|
51
|
-
continue;
|
|
52
|
-
if (item['type'] === 'diff') {
|
|
53
|
-
diffs.push({ path: item['path'], oldText: item['oldText'] ?? null, newText: item['newText'] ?? '' });
|
|
54
|
-
}
|
|
55
|
-
else if (item['type'] === 'content') {
|
|
56
|
-
const text = contentText(item['content']);
|
|
57
|
-
if (text)
|
|
58
|
-
texts.push(text);
|
|
59
|
-
}
|
|
60
|
-
else if (item['type'] === 'terminal' && item['terminalId']) {
|
|
61
|
-
texts.push(`[terminal ${item['terminalId']}]`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (diffs.length && texts.length)
|
|
65
|
-
return { diffs, text: texts.join('\n') };
|
|
66
|
-
if (diffs.length)
|
|
67
|
-
return diffs.length === 1 ? diffs[0] : { diffs };
|
|
68
|
-
if (texts.length)
|
|
69
|
-
return texts.join('\n');
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
/** Engine cursor.js:65-76. Shell `{stdout, stderr, exitCode}` -> `{text?, exitCode?}`. */
|
|
73
|
-
function rawOutputValue(rawOutput) {
|
|
74
|
-
if (rawOutput === undefined || rawOutput === null)
|
|
75
|
-
return undefined;
|
|
76
|
-
if (typeof rawOutput !== 'object')
|
|
77
|
-
return rawOutput;
|
|
78
|
-
const record = rawOutput;
|
|
79
|
-
if (typeof record['stdout'] === 'string' || typeof record['stderr'] === 'string') {
|
|
80
|
-
const text = [record['stdout'], record['stderr']].filter(Boolean).join('\n').trimEnd();
|
|
81
|
-
return {
|
|
82
|
-
...(text ? { text } : {}),
|
|
83
|
-
...(record['exitCode'] !== undefined ? { exitCode: record['exitCode'] } : {}),
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
return rawOutput;
|
|
87
|
-
}
|
|
88
|
-
/** Engine cursor.js:78-87. Merge an update into the known tool row (title/kind/input stick). */
|
|
89
|
-
function toolData(state, toolCallId, update = {}) {
|
|
90
|
-
const known = state.tools.get(toolCallId) || {};
|
|
91
|
-
const next = {
|
|
92
|
-
toolName: update['title'] || known.toolName || 'Tool',
|
|
93
|
-
kind: ACP_TOOL_KINDS[update['kind']] || known.kind || undefined,
|
|
94
|
-
input: update['rawInput'] !== undefined ? update['rawInput'] : known.input,
|
|
95
|
-
};
|
|
96
|
-
state.tools.set(toolCallId, next);
|
|
97
|
-
return next;
|
|
98
|
-
}
|
|
99
|
-
/** Build the Cursor normalizer over injected event constructors. */
|
|
100
|
-
export function createCursorNormalizer(events) {
|
|
101
|
-
const { errorEvent, reasoningDelta, textDelta, toolCompleted, toolStarted, toolUpdated, usageFinal, } = events;
|
|
102
|
-
/**
|
|
103
|
-
* Engine cursor.js:89-149. One ACP session/update notification -> amalgm
|
|
104
|
-
* events. `state` carries providerSessionId and per-turn tool
|
|
105
|
-
* bookkeeping; it is created per prompt.
|
|
106
|
-
*/
|
|
107
|
-
function normalizeCursorUpdate(updateInput, state) {
|
|
108
|
-
const update = updateInput;
|
|
109
|
-
const base = { providerSessionId: state.providerSessionId };
|
|
110
|
-
const kind = update?.['sessionUpdate'];
|
|
111
|
-
if (kind === 'agent_message_chunk') {
|
|
112
|
-
const text = contentText(update['content']);
|
|
113
|
-
return text ? [textDelta(text, base)] : [];
|
|
114
|
-
}
|
|
115
|
-
if (kind === 'agent_thought_chunk') {
|
|
116
|
-
const text = contentText(update['content']);
|
|
117
|
-
return text ? [reasoningDelta(text, base)] : [];
|
|
118
|
-
}
|
|
119
|
-
if (kind === 'tool_call') {
|
|
120
|
-
const data = toolData(state, update['toolCallId'], update);
|
|
121
|
-
return [toolStarted(update['toolCallId'], { ...base, ...data })];
|
|
122
|
-
}
|
|
123
|
-
if (kind === 'tool_call_update') {
|
|
124
|
-
const data = toolData(state, update['toolCallId'], update);
|
|
125
|
-
// Shell/execute results arrive as rawOutput ({exitCode, stdout, stderr});
|
|
126
|
-
// file edits arrive as content diff items.
|
|
127
|
-
const output = toolOutput(update['content']) ?? rawOutputValue(update['rawOutput']);
|
|
128
|
-
if (update['status'] === 'completed' || update['status'] === 'failed') {
|
|
129
|
-
state.tools.delete(update['toolCallId']);
|
|
130
|
-
return [toolCompleted(update['toolCallId'], {
|
|
131
|
-
...base,
|
|
132
|
-
...data,
|
|
133
|
-
...(output !== undefined ? { output } : {}),
|
|
134
|
-
isError: update['status'] === 'failed',
|
|
135
|
-
...(update['status'] === 'failed' ? { error: output || 'Tool call failed' } : {}),
|
|
136
|
-
})];
|
|
137
|
-
}
|
|
138
|
-
return [toolUpdated(update['toolCallId'], {
|
|
139
|
-
...base,
|
|
140
|
-
toolName: data.toolName,
|
|
141
|
-
kind: data.kind,
|
|
142
|
-
...(update['rawInput'] !== undefined ? { inputDelta: update['rawInput'] } : {}),
|
|
143
|
-
...(output !== undefined ? { output } : {}),
|
|
144
|
-
})];
|
|
145
|
-
}
|
|
146
|
-
if (kind === 'usage_update') {
|
|
147
|
-
// Cursor does not emit these today; mapped so context tracking lights up
|
|
148
|
-
// the moment the agent ships the ACP session-usage extension.
|
|
149
|
-
return [usageFinal({
|
|
150
|
-
usedTokens: update['used'],
|
|
151
|
-
maxTokens: update['size'],
|
|
152
|
-
costUsd: update['cost']?.amount ?? null,
|
|
153
|
-
operation: 'context_snapshot',
|
|
154
|
-
billable: false,
|
|
155
|
-
exact: false,
|
|
156
|
-
source: 'cursor_acp_usage_update',
|
|
157
|
-
}, base)];
|
|
158
|
-
}
|
|
159
|
-
if (kind === 'error') {
|
|
160
|
-
return [errorEvent(update['message'] || 'Cursor agent error', base)];
|
|
161
|
-
}
|
|
162
|
-
// Intentionally ignored: user_message_chunk (session/load replay),
|
|
163
|
-
// session_info_update (amalgm owns titles), available_commands_update,
|
|
164
|
-
// current_mode_update, config_options_update, plan.
|
|
165
|
-
return [];
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Engine cursor.js:151-168. ACP PromptResponse.usage (session-usage RFD)
|
|
169
|
-
* -> exact turn usage. Cursor does not populate this today; the mapping
|
|
170
|
-
* is here for when it does.
|
|
171
|
-
*/
|
|
172
|
-
function cursorPromptUsage(usageInput, base = {}) {
|
|
173
|
-
const usage = usageInput;
|
|
174
|
-
if (!usage || typeof usage !== 'object')
|
|
175
|
-
return null;
|
|
176
|
-
const total = Number(usage['total_tokens'] ?? usage['totalTokens']);
|
|
177
|
-
if (!Number.isFinite(total) || total <= 0)
|
|
178
|
-
return null;
|
|
179
|
-
return usageFinal({
|
|
180
|
-
inputTokens: usage['input_tokens'] ?? usage['inputTokens'],
|
|
181
|
-
outputTokens: usage['output_tokens'] ?? usage['outputTokens'],
|
|
182
|
-
cacheReadTokens: usage['cached_read_tokens'] ?? usage['cacheReadTokens'],
|
|
183
|
-
cacheWriteTokens: usage['cached_write_tokens'] ?? usage['cacheWriteTokens'],
|
|
184
|
-
thoughtTokens: usage['thought_tokens'] ?? usage['thoughtTokens'],
|
|
185
|
-
operation: 'chat_turn',
|
|
186
|
-
billable: true,
|
|
187
|
-
exact: true,
|
|
188
|
-
source: 'cursor_acp_prompt_usage',
|
|
189
|
-
}, base);
|
|
190
|
-
}
|
|
191
|
-
return {
|
|
192
|
-
normalizeCursorUpdate,
|
|
193
|
-
cursorPromptUsage,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
//# sourceMappingURL=cursor.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/normalizers/cursor.ts"],"names":[],"mappings":"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"}
|