@amalgm/chat 0.2.7 → 0.2.9-main.34175712248
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 +21 -0
- package/README.md +14 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/normalizers/claude.d.ts +46 -46
- package/dist/normalizers/codex.d.ts +23 -23
- package/dist/sessions/external-message.d.ts +30 -0
- package/dist/sessions/external-message.d.ts.map +1 -0
- package/dist/sessions/external-message.js +104 -0
- package/dist/sessions/external-message.js.map +1 -0
- package/dist/sessions/index.d.ts +2 -0
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +1 -0
- package/dist/sessions/index.js.map +1 -1
- package/package.json +26 -2
package/PURPOSE.md
CHANGED
|
@@ -33,6 +33,8 @@ automations, and third-party apps must all use the same public SDK.
|
|
|
33
33
|
capability, never a second session, turn, or transcript owner.
|
|
34
34
|
- An **agent run** is one idempotently named new conversation whose exact
|
|
35
35
|
installed-agent execution is resolved by the host before its first turn.
|
|
36
|
+
- An **external message** is one idempotently named turn in a provider thread
|
|
37
|
+
whose stable thread mapping supplies the durable conversation id.
|
|
36
38
|
|
|
37
39
|
## Workstream 1 axioms
|
|
38
40
|
|
|
@@ -139,6 +141,10 @@ automations, and third-party apps must all use the same public SDK.
|
|
|
139
141
|
37. Agent-run occurrence context is a separate official ACP JSON resource,
|
|
140
142
|
never system instructions or ambient host state. The host resolves the
|
|
141
143
|
installation to one exact execution contract before Chat starts it.
|
|
144
|
+
38. An external channel thread names one durable conversation. Its first
|
|
145
|
+
admitted message creates that exact conversation; every later message
|
|
146
|
+
resumes it, and the provider message id is the stable turn id. Chat never
|
|
147
|
+
infers a thread from a subject or chooses a recipient.
|
|
142
148
|
|
|
143
149
|
## North-star proof
|
|
144
150
|
|
|
@@ -196,3 +202,18 @@ instructions. Amp, Gemini CLI, and Kiro were not installed for individual
|
|
|
196
202
|
acceptance tests.
|
|
197
203
|
|
|
198
204
|
The public contracts live in `docs/contracts/` and the shipped Chat skill.
|
|
205
|
+
|
|
206
|
+
## Managed package delivery
|
|
207
|
+
|
|
208
|
+
Managed package delivery starts from a clean, exact main or preview source
|
|
209
|
+
commit. The workflow occurrence supplies only its generated version and source
|
|
210
|
+
record; tests run against those candidate inputs before packing. Every native
|
|
211
|
+
gate and publication use that same tarball and integrity. A candidate tag makes
|
|
212
|
+
bytes available to release assembly; it never promotes an installed runtime.
|
|
213
|
+
Release tooling remains available inside each owner repository so a developer
|
|
214
|
+
or CI job never needs access to another private product repository.
|
|
215
|
+
Registry credentials are available only to the final protected publication job,
|
|
216
|
+
after every native examination proves the exact candidate bytes.
|
|
217
|
+
Native consumers install the archive as a dependency, so SDK development
|
|
218
|
+
dependencies never become an end-user installation requirement.
|
|
219
|
+
Each admitted owner gate proves its actual checkout equals the managed source.
|
package/README.md
CHANGED
|
@@ -103,7 +103,17 @@ npm test
|
|
|
103
103
|
npm pack --dry-run
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
Managed npm delivery uses `.github/workflows/publish-package.yml` after the
|
|
107
|
+
exact main/preview owner checks pass. The occurrence generates a unique
|
|
108
|
+
prerelease version and records its source SHA; it reruns the owner suite, packs
|
|
109
|
+
once, and installs that tarball on Linux, macOS and Windows before publication.
|
|
110
|
+
The `candidate-main`/`candidate-preview` tags are release-assembly inputs and
|
|
111
|
+
never select installed runtimes. `package.json` declares this owner's gates,
|
|
112
|
+
CLI probes, peer-only exports and lifecycle permissions. The standalone runner
|
|
113
|
+
under `scripts/release/` is intentionally copied across owners to preserve
|
|
114
|
+
private repository access boundaries. The final publish step uses the `NPM_TOKEN`
|
|
115
|
+
secret in the `npm-release` environment. Where npm trusted publishing is
|
|
116
|
+
configured for this repository's `publish-package.yml` and that environment,
|
|
117
|
+
the token can be omitted. Authentication does not replace native certification,
|
|
118
|
+
exact source records or artifact integrity; private source repositories do not
|
|
119
|
+
receive npm's public-source provenance.
|
package/dist/index.d.ts
CHANGED
|
@@ -11,5 +11,7 @@ export * as conversations from './conversations/index.js';
|
|
|
11
11
|
export * as mcp from './mcp/index.js';
|
|
12
12
|
export { Chat, ChatTurnStream, ChatSession, InterruptUnsupportedError, SessionAgentMismatchError, SessionAlreadyExistsError, SessionBusyError, SessionNotFoundError, SubscriberBackpressureError, TurnStreamError, } from './sessions/index.js';
|
|
13
13
|
export type { ChatRuntimePort, InterruptResult, RuntimeInterruptRequest, } from './sessions/index.js';
|
|
14
|
+
export { createExternalMessageRunner } from './sessions/index.js';
|
|
15
|
+
export type { ExternalMessageAdmission, ExternalMessageExecution, ExternalMessageInput, ExternalMessageRunner, } from './sessions/index.js';
|
|
14
16
|
export type { ClockMsPort, ClockIsoPort, Sha256HexPort, RandomUuidPort } from './ports.js';
|
|
15
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,aAAa,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,eAAe,EACf,eAAe,EACf,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,aAAa,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,eAAe,EACf,eAAe,EACf,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,4 +10,5 @@ export * as sessions from './sessions/index.js';
|
|
|
10
10
|
export * as conversations from './conversations/index.js';
|
|
11
11
|
export * as mcp from './mcp/index.js';
|
|
12
12
|
export { Chat, ChatTurnStream, ChatSession, InterruptUnsupportedError, SessionAgentMismatchError, SessionAlreadyExistsError, SessionBusyError, SessionNotFoundError, SubscriberBackpressureError, TurnStreamError, } from './sessions/index.js';
|
|
13
|
+
export { createExternalMessageRunner } from './sessions/index.js';
|
|
13
14
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,aAAa,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,aAAa,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -235,6 +235,29 @@ export declare function createClaudeNormalizer(events: EventConstructors): {
|
|
|
235
235
|
method?: string | undefined;
|
|
236
236
|
payload?: unknown;
|
|
237
237
|
} | undefined;
|
|
238
|
+
} | {
|
|
239
|
+
ts: number;
|
|
240
|
+
type: "compaction.started";
|
|
241
|
+
trigger: "auto" | "manual" | "model_triggered";
|
|
242
|
+
providerSessionId?: string | null | undefined;
|
|
243
|
+
raw?: {
|
|
244
|
+
source: string;
|
|
245
|
+
method?: string | undefined;
|
|
246
|
+
payload?: unknown;
|
|
247
|
+
} | undefined;
|
|
248
|
+
} | {
|
|
249
|
+
ts: number;
|
|
250
|
+
type: "compaction.finished";
|
|
251
|
+
trigger: "auto" | "manual" | "model_triggered";
|
|
252
|
+
providerSessionId?: string | null | undefined;
|
|
253
|
+
raw?: {
|
|
254
|
+
source: string;
|
|
255
|
+
method?: string | undefined;
|
|
256
|
+
payload?: unknown;
|
|
257
|
+
} | undefined;
|
|
258
|
+
preTokens?: number | null | undefined;
|
|
259
|
+
postTokens?: number | null | undefined;
|
|
260
|
+
durationMs?: number | null | undefined;
|
|
238
261
|
} | {
|
|
239
262
|
ts: number;
|
|
240
263
|
type: "warning";
|
|
@@ -310,29 +333,6 @@ export declare function createClaudeNormalizer(events: EventConstructors): {
|
|
|
310
333
|
source: string;
|
|
311
334
|
exact: boolean;
|
|
312
335
|
} | undefined;
|
|
313
|
-
} | {
|
|
314
|
-
ts: number;
|
|
315
|
-
type: "compaction.started";
|
|
316
|
-
trigger: "auto" | "manual" | "model_triggered";
|
|
317
|
-
providerSessionId?: string | null | undefined;
|
|
318
|
-
raw?: {
|
|
319
|
-
source: string;
|
|
320
|
-
method?: string | undefined;
|
|
321
|
-
payload?: unknown;
|
|
322
|
-
} | undefined;
|
|
323
|
-
} | {
|
|
324
|
-
ts: number;
|
|
325
|
-
type: "compaction.finished";
|
|
326
|
-
trigger: "auto" | "manual" | "model_triggered";
|
|
327
|
-
providerSessionId?: string | null | undefined;
|
|
328
|
-
raw?: {
|
|
329
|
-
source: string;
|
|
330
|
-
method?: string | undefined;
|
|
331
|
-
payload?: unknown;
|
|
332
|
-
} | undefined;
|
|
333
|
-
preTokens?: number | null | undefined;
|
|
334
|
-
postTokens?: number | null | undefined;
|
|
335
|
-
durationMs?: number | null | undefined;
|
|
336
336
|
})[];
|
|
337
337
|
normalizeClaudeMessage: (message: AnyRecord | null | undefined, state?: ClaudeNormalizerState | null) => ({
|
|
338
338
|
ts: number;
|
|
@@ -514,6 +514,29 @@ export declare function createClaudeNormalizer(events: EventConstructors): {
|
|
|
514
514
|
method?: string | undefined;
|
|
515
515
|
payload?: unknown;
|
|
516
516
|
} | undefined;
|
|
517
|
+
} | {
|
|
518
|
+
ts: number;
|
|
519
|
+
type: "compaction.started";
|
|
520
|
+
trigger: "auto" | "manual" | "model_triggered";
|
|
521
|
+
providerSessionId?: string | null | undefined;
|
|
522
|
+
raw?: {
|
|
523
|
+
source: string;
|
|
524
|
+
method?: string | undefined;
|
|
525
|
+
payload?: unknown;
|
|
526
|
+
} | undefined;
|
|
527
|
+
} | {
|
|
528
|
+
ts: number;
|
|
529
|
+
type: "compaction.finished";
|
|
530
|
+
trigger: "auto" | "manual" | "model_triggered";
|
|
531
|
+
providerSessionId?: string | null | undefined;
|
|
532
|
+
raw?: {
|
|
533
|
+
source: string;
|
|
534
|
+
method?: string | undefined;
|
|
535
|
+
payload?: unknown;
|
|
536
|
+
} | undefined;
|
|
537
|
+
preTokens?: number | null | undefined;
|
|
538
|
+
postTokens?: number | null | undefined;
|
|
539
|
+
durationMs?: number | null | undefined;
|
|
517
540
|
} | {
|
|
518
541
|
ts: number;
|
|
519
542
|
type: "warning";
|
|
@@ -589,29 +612,6 @@ export declare function createClaudeNormalizer(events: EventConstructors): {
|
|
|
589
612
|
source: string;
|
|
590
613
|
exact: boolean;
|
|
591
614
|
} | undefined;
|
|
592
|
-
} | {
|
|
593
|
-
ts: number;
|
|
594
|
-
type: "compaction.started";
|
|
595
|
-
trigger: "auto" | "manual" | "model_triggered";
|
|
596
|
-
providerSessionId?: string | null | undefined;
|
|
597
|
-
raw?: {
|
|
598
|
-
source: string;
|
|
599
|
-
method?: string | undefined;
|
|
600
|
-
payload?: unknown;
|
|
601
|
-
} | undefined;
|
|
602
|
-
} | {
|
|
603
|
-
ts: number;
|
|
604
|
-
type: "compaction.finished";
|
|
605
|
-
trigger: "auto" | "manual" | "model_triggered";
|
|
606
|
-
providerSessionId?: string | null | undefined;
|
|
607
|
-
raw?: {
|
|
608
|
-
source: string;
|
|
609
|
-
method?: string | undefined;
|
|
610
|
-
payload?: unknown;
|
|
611
|
-
} | undefined;
|
|
612
|
-
preTokens?: number | null | undefined;
|
|
613
|
-
postTokens?: number | null | undefined;
|
|
614
|
-
durationMs?: number | null | undefined;
|
|
615
615
|
})[];
|
|
616
616
|
stableStringify: typeof stableStringify;
|
|
617
617
|
stringifyClaudeContent: typeof stringifyClaudeContent;
|
|
@@ -243,6 +243,29 @@ export declare function createCodexNormalizer(events: EventConstructors): {
|
|
|
243
243
|
method?: string | undefined;
|
|
244
244
|
payload?: unknown;
|
|
245
245
|
} | undefined;
|
|
246
|
+
} | {
|
|
247
|
+
ts: number;
|
|
248
|
+
type: "compaction.started";
|
|
249
|
+
trigger: "auto" | "manual" | "model_triggered";
|
|
250
|
+
providerSessionId?: string | null | undefined;
|
|
251
|
+
raw?: {
|
|
252
|
+
source: string;
|
|
253
|
+
method?: string | undefined;
|
|
254
|
+
payload?: unknown;
|
|
255
|
+
} | undefined;
|
|
256
|
+
} | {
|
|
257
|
+
ts: number;
|
|
258
|
+
type: "compaction.finished";
|
|
259
|
+
trigger: "auto" | "manual" | "model_triggered";
|
|
260
|
+
providerSessionId?: string | null | undefined;
|
|
261
|
+
raw?: {
|
|
262
|
+
source: string;
|
|
263
|
+
method?: string | undefined;
|
|
264
|
+
payload?: unknown;
|
|
265
|
+
} | undefined;
|
|
266
|
+
preTokens?: number | null | undefined;
|
|
267
|
+
postTokens?: number | null | undefined;
|
|
268
|
+
durationMs?: number | null | undefined;
|
|
246
269
|
} | {
|
|
247
270
|
ts: number;
|
|
248
271
|
type: "warning";
|
|
@@ -318,29 +341,6 @@ export declare function createCodexNormalizer(events: EventConstructors): {
|
|
|
318
341
|
source: string;
|
|
319
342
|
exact: boolean;
|
|
320
343
|
} | undefined;
|
|
321
|
-
} | {
|
|
322
|
-
ts: number;
|
|
323
|
-
type: "compaction.started";
|
|
324
|
-
trigger: "auto" | "manual" | "model_triggered";
|
|
325
|
-
providerSessionId?: string | null | undefined;
|
|
326
|
-
raw?: {
|
|
327
|
-
source: string;
|
|
328
|
-
method?: string | undefined;
|
|
329
|
-
payload?: unknown;
|
|
330
|
-
} | undefined;
|
|
331
|
-
} | {
|
|
332
|
-
ts: number;
|
|
333
|
-
type: "compaction.finished";
|
|
334
|
-
trigger: "auto" | "manual" | "model_triggered";
|
|
335
|
-
providerSessionId?: string | null | undefined;
|
|
336
|
-
raw?: {
|
|
337
|
-
source: string;
|
|
338
|
-
method?: string | undefined;
|
|
339
|
-
payload?: unknown;
|
|
340
|
-
} | undefined;
|
|
341
|
-
preTokens?: number | null | undefined;
|
|
342
|
-
postTokens?: number | null | undefined;
|
|
343
|
-
durationMs?: number | null | undefined;
|
|
344
344
|
})[];
|
|
345
345
|
};
|
|
346
346
|
/** The Codex normalizer set, closed over injected constructors. */
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ConversationRecord } from '../conversations/types.js';
|
|
2
|
+
import type { ExecutionContract } from '../execution/contract.js';
|
|
3
|
+
import type { Chat } from './chat.js';
|
|
4
|
+
export interface ExternalMessageInput {
|
|
5
|
+
readonly origin: string;
|
|
6
|
+
readonly threadId: string;
|
|
7
|
+
readonly sessionId: string;
|
|
8
|
+
readonly messageId: string;
|
|
9
|
+
readonly startsSession: boolean;
|
|
10
|
+
readonly title: string;
|
|
11
|
+
readonly message: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ExternalMessageExecution {
|
|
14
|
+
readonly execution: ExecutionContract;
|
|
15
|
+
readonly title?: string;
|
|
16
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
17
|
+
}
|
|
18
|
+
export interface ExternalMessageAdmission {
|
|
19
|
+
readonly sessionId: string;
|
|
20
|
+
readonly turnId: string;
|
|
21
|
+
readonly completion: Promise<unknown>;
|
|
22
|
+
}
|
|
23
|
+
export interface ExternalMessageRunner {
|
|
24
|
+
admit(input: ExternalMessageInput): Promise<ExternalMessageAdmission>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createExternalMessageRunner<Binding, RuntimeSession>(chat: Chat<Binding, RuntimeSession>, options: Readonly<{
|
|
27
|
+
resolveNew(input: ExternalMessageInput): Promise<ExternalMessageExecution> | ExternalMessageExecution;
|
|
28
|
+
resolveExisting(record: ConversationRecord): Promise<ExternalMessageExecution> | ExternalMessageExecution;
|
|
29
|
+
}>): ExternalMessageRunner;
|
|
30
|
+
//# sourceMappingURL=external-message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-message.d.ts","sourceRoot":"","sources":["../../src/sessions/external-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACvE;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,cAAc,EACjE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,EACnC,OAAO,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,wBAAwB,CAAC,GAAG,wBAAwB,CAAC;IACtG,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,wBAAwB,CAAC,GAAG,wBAAwB,CAAC;CAC3G,CAAC,GACD,qBAAqB,CAwDvB"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export function createExternalMessageRunner(chat, options) {
|
|
2
|
+
return Object.freeze({
|
|
3
|
+
async admit(input) {
|
|
4
|
+
validate(input);
|
|
5
|
+
const prior = await existingAdmission(chat, input.sessionId, input.messageId);
|
|
6
|
+
if (prior)
|
|
7
|
+
return prior;
|
|
8
|
+
let session;
|
|
9
|
+
let execution;
|
|
10
|
+
if (input.startsSession) {
|
|
11
|
+
const resolved = await options.resolveNew(input);
|
|
12
|
+
execution = await chat.prepareExecution(`external:${input.origin}:${input.sessionId}`, resolved.execution);
|
|
13
|
+
try {
|
|
14
|
+
session = await chat.startSession({
|
|
15
|
+
sessionId: input.sessionId,
|
|
16
|
+
execution,
|
|
17
|
+
title: resolved.title ?? input.title,
|
|
18
|
+
origin: input.origin,
|
|
19
|
+
originId: input.threadId,
|
|
20
|
+
metadata: {
|
|
21
|
+
...(resolved.metadata ?? {}),
|
|
22
|
+
externalThreadId: input.threadId,
|
|
23
|
+
externalOrigin: input.origin,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (!hasCode(error, 'SESSION_ALREADY_EXISTS'))
|
|
29
|
+
throw error;
|
|
30
|
+
session = await chat.resumeSession({ sessionId: input.sessionId, execution });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
try {
|
|
35
|
+
const resumed = await chat.resumeStoredSession(input.sessionId);
|
|
36
|
+
session = resumed.session;
|
|
37
|
+
execution = resumed.execution;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (!hasCode(error, 'SESSION_NOT_FOUND'))
|
|
41
|
+
throw error;
|
|
42
|
+
const record = await chat.inspectSession(input.sessionId);
|
|
43
|
+
const resolved = await options.resolveExisting(record);
|
|
44
|
+
execution = await chat.prepareExecution(`external:${input.origin}:${input.sessionId}`, resolved.execution);
|
|
45
|
+
session = await chat.resumeSession({ sessionId: input.sessionId, execution });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const stream = await session.send({
|
|
49
|
+
execution,
|
|
50
|
+
clientTurnId: input.messageId,
|
|
51
|
+
userMessageId: input.messageId,
|
|
52
|
+
prompt: externalPrompt(input),
|
|
53
|
+
});
|
|
54
|
+
return Object.freeze({
|
|
55
|
+
sessionId: input.sessionId,
|
|
56
|
+
turnId: input.messageId,
|
|
57
|
+
completion: stream.completion,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async function existingAdmission(chat, sessionId, turnId) {
|
|
63
|
+
try {
|
|
64
|
+
const replay = await chat.replayTurn(sessionId, turnId);
|
|
65
|
+
const completion = replay.turn.status !== 'running' ? Promise.resolve() : (async () => {
|
|
66
|
+
for await (const _update of chat.reconnectTurn(sessionId, turnId)) { /* wait for seal */ }
|
|
67
|
+
})();
|
|
68
|
+
return Object.freeze({ sessionId, turnId, completion });
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (hasCode(error, 'SESSION_NOT_FOUND'))
|
|
72
|
+
return null;
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function externalPrompt(input) {
|
|
77
|
+
return {
|
|
78
|
+
parts: [{
|
|
79
|
+
type: 'text',
|
|
80
|
+
text: [
|
|
81
|
+
`The account owner sent this ${input.origin} message:`,
|
|
82
|
+
'',
|
|
83
|
+
input.message,
|
|
84
|
+
'',
|
|
85
|
+
`Your ordinary assistant response is not sent to the user. Work on the request, then call the Channels send tool with channel ${JSON.stringify(input.origin)} for each message you deliberately want to send back. Do not stream partial progress through Channels.`,
|
|
86
|
+
].join('\n'),
|
|
87
|
+
}],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function validate(input) {
|
|
91
|
+
if (typeof input.startsSession !== 'boolean') {
|
|
92
|
+
throw new TypeError('startsSession must be a boolean');
|
|
93
|
+
}
|
|
94
|
+
for (const [name, value] of Object.entries(input)) {
|
|
95
|
+
if (name === 'startsSession')
|
|
96
|
+
continue;
|
|
97
|
+
if (typeof value !== 'string' || !value.trim())
|
|
98
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function hasCode(error, code) {
|
|
102
|
+
return Boolean(error && typeof error === 'object' && error.code === code);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=external-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-message.js","sourceRoot":"","sources":["../../src/sessions/external-message.ts"],"names":[],"mappings":"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"}
|
package/dist/sessions/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export type { ChatOptions, ChatRuntimePort, InterruptResult, ReconnectOptions, ResumeSessionOptions, ResumeStoredSessionResult, RuntimePromptRequest, RuntimeInterruptRequest, RuntimeResumeRequest, RuntimeStartRequest, SendOptions, StartSessionOptions, TurnReplay, } from './chat.js';
|
|
2
|
+
export { createExternalMessageRunner } from './external-message.js';
|
|
3
|
+
export type { ExternalMessageAdmission, ExternalMessageExecution, ExternalMessageInput, ExternalMessageRunner, } from './external-message.js';
|
|
2
4
|
export { Chat, ChatTurnStream, ChatSession, InterruptUnsupportedError, SessionAgentMismatchError, SessionAlreadyExistsError, SessionBusyError, SessionNotFoundError, SubscriberBackpressureError, TurnStreamError, } from './chat.js';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,UAAU,GACX,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,UAAU,GACX,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,WAAW,CAAC"}
|
package/dist/sessions/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
export { createExternalMessageRunner } from './external-message.js';
|
|
1
2
|
export { Chat, ChatTurnStream, ChatSession, InterruptUnsupportedError, SessionAgentMismatchError, SessionAlreadyExistsError, SessionBusyError, SessionNotFoundError, SubscriberBackpressureError, TurnStreamError, } from './chat.js';
|
|
2
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAOpE,OAAO,EACL,IAAI,EACJ,cAAc,EACd,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,WAAW,CAAC"}
|
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.34175712248",
|
|
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": "42411e61e753e13bffdd3b0ca7628577691dd910",
|
|
122
|
+
"amalgmSource": {
|
|
123
|
+
"repository": "amalgm-inc/amalgm-chat",
|
|
124
|
+
"branch": "main",
|
|
125
|
+
"commit": "42411e61e753e13bffdd3b0ca7628577691dd910",
|
|
126
|
+
"occurrence": "34175712248"
|
|
103
127
|
}
|
|
104
128
|
}
|