@copilotkit/channels-core 0.8.1 → 0.9.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/README.md +2 -2
- package/dist/canonical-run-loop.test.js +110 -3
- package/dist/channel-memory.test.js +2 -0
- package/dist/codec.d.ts +6 -4
- package/dist/codec.d.ts.map +1 -1
- package/dist/create-channel.d.ts +19 -2
- package/dist/create-channel.d.ts.map +1 -1
- package/dist/create-channel.js +6 -0
- package/dist/create-channel.test.js +8 -0
- package/dist/hitl-continuation.test.js +17 -4
- package/dist/identity.d.ts +44 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +31 -0
- package/dist/identity.test.js +28 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/interrupt-event-echo.test.d.ts +2 -0
- package/dist/interrupt-event-echo.test.d.ts.map +1 -0
- package/dist/interrupt-event-echo.test.js +161 -0
- package/dist/platform-adapter.d.ts +3 -1
- package/dist/platform-adapter.d.ts.map +1 -1
- package/dist/run-loop.d.ts +21 -2
- package/dist/run-loop.d.ts.map +1 -1
- package/dist/run-loop.js +46 -5
- package/dist/run-loop.test.js +56 -0
- package/dist/sanitize-agent-events.test.js +27 -6
- package/dist/testing/fake-agent.d.ts +3 -1
- package/dist/testing/fake-agent.d.ts.map +1 -1
- package/dist/testing/fake-agent.js +4 -1
- package/dist/thread.d.ts +22 -0
- package/dist/thread.d.ts.map +1 -1
- package/dist/thread.js +67 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -85,9 +85,9 @@ const channel = createChannel({
|
|
|
85
85
|
|
|
86
86
|
const runtime = new CopilotRuntime({
|
|
87
87
|
intelligence: new CopilotKitIntelligence({
|
|
88
|
-
// apiUrl and wsUrl default to
|
|
88
|
+
// apiUrl and wsUrl default to cloud-hosted CopilotKit Intelligence — override
|
|
89
89
|
// both together only for a self-hosted deployment.
|
|
90
|
-
apiKey: process.env.
|
|
90
|
+
apiKey: process.env.CPK_INTELLIGENCE_API_KEY!, // free tier available
|
|
91
91
|
}),
|
|
92
92
|
channels: [channel],
|
|
93
93
|
});
|
|
@@ -8,7 +8,7 @@ const canonicalRun = {
|
|
|
8
8
|
threadId: "canonical-thread",
|
|
9
9
|
runId: "canonical-run",
|
|
10
10
|
};
|
|
11
|
-
function lifecycleBatch(runId, middle) {
|
|
11
|
+
function lifecycleBatch(runId, middle, usage, finishReason) {
|
|
12
12
|
return [
|
|
13
13
|
{
|
|
14
14
|
type: EventType.RUN_STARTED,
|
|
@@ -20,6 +20,8 @@ function lifecycleBatch(runId, middle) {
|
|
|
20
20
|
type: EventType.RUN_FINISHED,
|
|
21
21
|
threadId: "inner-thread",
|
|
22
22
|
runId,
|
|
23
|
+
...(usage ? { usage } : {}),
|
|
24
|
+
...(finishReason !== undefined ? { finishReason } : {}),
|
|
23
25
|
},
|
|
24
26
|
];
|
|
25
27
|
}
|
|
@@ -30,7 +32,7 @@ function textEvent(messageId, text) {
|
|
|
30
32
|
delta: text,
|
|
31
33
|
};
|
|
32
34
|
}
|
|
33
|
-
async function emitBatch(subscriber, agent, runId, middle) {
|
|
35
|
+
async function emitBatch(subscriber, agent, runId, middle, usage, finishReason) {
|
|
34
36
|
const input = {
|
|
35
37
|
threadId: agent.threadId,
|
|
36
38
|
runId,
|
|
@@ -46,7 +48,7 @@ async function emitBatch(subscriber, agent, runId, middle) {
|
|
|
46
48
|
agent,
|
|
47
49
|
input,
|
|
48
50
|
};
|
|
49
|
-
for (const event of lifecycleBatch(runId, middle)) {
|
|
51
|
+
for (const event of lifecycleBatch(runId, middle, usage, finishReason)) {
|
|
50
52
|
await subscriber.onEvent?.({ ...params, event });
|
|
51
53
|
switch (event.type) {
|
|
52
54
|
case EventType.RUN_STARTED:
|
|
@@ -80,6 +82,111 @@ async function emitBatch(subscriber, agent, runId, middle) {
|
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
}
|
|
85
|
+
test("managed runAgentLoop aggregates token usage across agent iterations", async () => {
|
|
86
|
+
let agent;
|
|
87
|
+
agent = new FakeAgent([
|
|
88
|
+
(subscriber) => emitBatch(subscriber, agent, "inner-run-1", [{ type: EventType.TOOL_CALL_END, toolCallId: "tool-call-1" }], [
|
|
89
|
+
{
|
|
90
|
+
provider: "openai",
|
|
91
|
+
model: "gpt-5-mini",
|
|
92
|
+
inputTokens: 10,
|
|
93
|
+
outputTokens: 4,
|
|
94
|
+
totalTokens: 14,
|
|
95
|
+
},
|
|
96
|
+
]),
|
|
97
|
+
(subscriber) => emitBatch(subscriber, agent, "inner-run-2", [], [
|
|
98
|
+
{
|
|
99
|
+
provider: "openai",
|
|
100
|
+
model: "gpt-5-mini",
|
|
101
|
+
inputTokens: 12,
|
|
102
|
+
outputTokens: 3,
|
|
103
|
+
totalTokens: 15,
|
|
104
|
+
},
|
|
105
|
+
]),
|
|
106
|
+
]);
|
|
107
|
+
const { renderer } = setupRenderer();
|
|
108
|
+
const ingestedEvents = [];
|
|
109
|
+
const echo = {
|
|
110
|
+
name: "echo",
|
|
111
|
+
description: "Return the value.",
|
|
112
|
+
parameters: z.object({ value: z.string() }),
|
|
113
|
+
handler: ({ value }) => value,
|
|
114
|
+
};
|
|
115
|
+
await runAgentLoop({
|
|
116
|
+
agent,
|
|
117
|
+
renderer,
|
|
118
|
+
tools: new Map([["echo", echo]]),
|
|
119
|
+
toolDescriptors: [],
|
|
120
|
+
context: [],
|
|
121
|
+
makeToolCtx: () => {
|
|
122
|
+
throw new Error("tool context is not used by this test");
|
|
123
|
+
},
|
|
124
|
+
subscriber: {
|
|
125
|
+
onEvent: ({ event }) => {
|
|
126
|
+
ingestedEvents.push(event);
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
canonicalRun,
|
|
130
|
+
});
|
|
131
|
+
expect(ingestedEvents.at(-1)).toMatchObject({
|
|
132
|
+
type: EventType.RUN_FINISHED,
|
|
133
|
+
usage: [
|
|
134
|
+
{
|
|
135
|
+
provider: "openai",
|
|
136
|
+
model: "gpt-5-mini",
|
|
137
|
+
inputTokens: 22,
|
|
138
|
+
outputTokens: 7,
|
|
139
|
+
totalTokens: 29,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
test("managed runAgentLoop preserves the latest inner finish reason", async () => {
|
|
145
|
+
let agent;
|
|
146
|
+
agent = new FakeAgent([
|
|
147
|
+
(subscriber) => emitBatch(subscriber, agent, "inner-run-1", [], undefined, "length"),
|
|
148
|
+
(subscriber) => emitBatch(subscriber, agent, "inner-run-2", [], undefined, "stop"),
|
|
149
|
+
]);
|
|
150
|
+
const { renderer } = setupRenderer();
|
|
151
|
+
const ingestedEvents = [];
|
|
152
|
+
const echo = {
|
|
153
|
+
name: "echo",
|
|
154
|
+
description: "Return the value.",
|
|
155
|
+
parameters: z.object({ value: z.string() }),
|
|
156
|
+
handler: ({ value }) => value,
|
|
157
|
+
};
|
|
158
|
+
// Force a second iteration without depending on streamed tool-call content.
|
|
159
|
+
let calls = 0;
|
|
160
|
+
renderer.getCapturedToolCalls = () => calls++ === 0
|
|
161
|
+
? [
|
|
162
|
+
{
|
|
163
|
+
toolCallId: "tool-call-1",
|
|
164
|
+
toolCallName: "echo",
|
|
165
|
+
toolCallArgs: { value: "ok" },
|
|
166
|
+
},
|
|
167
|
+
]
|
|
168
|
+
: [];
|
|
169
|
+
await runAgentLoop({
|
|
170
|
+
agent,
|
|
171
|
+
renderer,
|
|
172
|
+
tools: new Map([["echo", echo]]),
|
|
173
|
+
toolDescriptors: [],
|
|
174
|
+
context: [],
|
|
175
|
+
makeToolCtx: () => {
|
|
176
|
+
throw new Error("tool context is not used by this test");
|
|
177
|
+
},
|
|
178
|
+
subscriber: {
|
|
179
|
+
onEvent: ({ event }) => {
|
|
180
|
+
ingestedEvents.push(event);
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
canonicalRun,
|
|
184
|
+
});
|
|
185
|
+
expect(ingestedEvents.at(-1)).toMatchObject({
|
|
186
|
+
type: EventType.RUN_FINISHED,
|
|
187
|
+
finishReason: "stop",
|
|
188
|
+
});
|
|
189
|
+
});
|
|
83
190
|
function setupRenderer(options = {}) {
|
|
84
191
|
const renderedEvents = [];
|
|
85
192
|
const renderedFinishMetadata = [];
|
|
@@ -65,6 +65,7 @@ test("project-only Memory works when Channel identity is null", async () => {
|
|
|
65
65
|
platform: "slack",
|
|
66
66
|
});
|
|
67
67
|
expect(lifecycle).toHaveBeenCalledWith(expect.objectContaining({
|
|
68
|
+
user: null,
|
|
68
69
|
memory: {
|
|
69
70
|
grant: { user: "none", project: "read-write" },
|
|
70
71
|
user: null,
|
|
@@ -96,6 +97,7 @@ test("a custom identity callback may map a non-human actor to personal Memory",
|
|
|
96
97
|
actor: { id: "sync-bot", kind: "bot", name: "Sync Bot" },
|
|
97
98
|
});
|
|
98
99
|
expect(lifecycle).toHaveBeenCalledWith(expect.objectContaining({
|
|
100
|
+
user: { id: "service:sync-bot", name: "Sync Bot" },
|
|
99
101
|
memory: {
|
|
100
102
|
grant: { user: "read", project: "none" },
|
|
101
103
|
user: { id: "service:sync-bot", name: "Sync Bot" },
|
package/dist/codec.d.ts
CHANGED
|
@@ -11,10 +11,12 @@ import type { ChannelNode } from "@copilotkit/channels-ui";
|
|
|
11
11
|
* excludes both — `renderEgress` is pure (IR → native payload); the actual
|
|
12
12
|
* send happens in the Gateway with Intelligence-owned credentials.
|
|
13
13
|
*
|
|
14
|
-
* TODO(
|
|
15
|
-
* ingress
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* TODO (untracked): add `normalizeIngress(raw): NeutralEvent` so both the local
|
|
15
|
+
* adapter and Intelligence's webhook ingress consume the same logic. The stated
|
|
16
|
+
* precondition is already met — the pure Slack ingress mapping (mention stripping,
|
|
17
|
+
* stable event-id derivation, real-user filtering, field extraction) now lives in
|
|
18
|
+
* `channels-slack/src/ingress-normalize.ts`. The original tracking ticket (OSS-363)
|
|
19
|
+
* was canceled 2026-07-01, superseded by OSS-401 — re-file before acting.
|
|
18
20
|
*/
|
|
19
21
|
export interface PlatformCodec {
|
|
20
22
|
readonly platform: string;
|
package/dist/codec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../src/codec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../src/codec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,YAAY,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;CAC1C"}
|
package/dist/create-channel.d.ts
CHANGED
|
@@ -20,6 +20,23 @@ export type LockConflictDecision = "drop" | "force";
|
|
|
20
20
|
* - `"drop"` — later turns are discarded while a turn is in flight.
|
|
21
21
|
*/
|
|
22
22
|
export type ChannelConcurrency = "parallel" | "serial" | "drop";
|
|
23
|
+
/**
|
|
24
|
+
* Public agent boundary for Channels.
|
|
25
|
+
*
|
|
26
|
+
* AG-UI agents from compatible client versions have the same runtime contract,
|
|
27
|
+
* but their private class fields make TypeScript treat the classes as distinct.
|
|
28
|
+
* Channels needs `clone()` at configuration time and validates the clone before
|
|
29
|
+
* each run.
|
|
30
|
+
*/
|
|
31
|
+
interface ChannelAgentInput {
|
|
32
|
+
threadId: string;
|
|
33
|
+
messages: unknown[];
|
|
34
|
+
state: unknown;
|
|
35
|
+
isRunning: boolean;
|
|
36
|
+
clone(): ChannelAgentInput;
|
|
37
|
+
runAgent(...args: never[]): Promise<unknown>;
|
|
38
|
+
addMessage(...args: never[]): void;
|
|
39
|
+
}
|
|
23
40
|
/**
|
|
24
41
|
* Isolate an agent for one turn via `clone()`.
|
|
25
42
|
*
|
|
@@ -47,7 +64,7 @@ export type ChannelConcurrency = "parallel" | "serial" | "drop";
|
|
|
47
64
|
* drops subclass state (see {@link warnOnCloneDroppedOwnFields}, which reports
|
|
48
65
|
* rather than refuses).
|
|
49
66
|
*/
|
|
50
|
-
export declare function isolateAgentInstance(prototype:
|
|
67
|
+
export declare function isolateAgentInstance(prototype: ChannelAgentInput, threadId: string): AbstractAgent;
|
|
51
68
|
/**
|
|
52
69
|
* Resolve effective turn concurrency from `store.concurrency` and legacy
|
|
53
70
|
* `store.onLockConflict`. Prefer `concurrency` when both are set.
|
|
@@ -220,7 +237,7 @@ export interface CreateChannelOptions<TStateSchema extends StandardSchemaV1 | un
|
|
|
220
237
|
* configure direct Slack with `slack({ replyContinuation })` instead.
|
|
221
238
|
*/
|
|
222
239
|
replyContinuation?: ReplyContinuationOptions;
|
|
223
|
-
agent?:
|
|
240
|
+
agent?: ChannelAgentInput | ((threadId: string) => ChannelAgentInput);
|
|
224
241
|
/**
|
|
225
242
|
* Tolerate the AG-UI event streams real agents emit. On by default.
|
|
226
243
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-channel.d.ts","sourceRoot":"","sources":["../src/create-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAUf,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,eAAe,EACf,UAAU,EAGV,WAAW,EACX,UAAU,EAEX,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,KAAK,EACV,0BAA0B,EAE3B,MAAM,wBAAwB,CAAC;AAiChC,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"create-channel.d.ts","sourceRoot":"","sources":["../src/create-channel.ts"],"names":[],"mappings":"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"}
|
package/dist/create-channel.js
CHANGED
|
@@ -90,6 +90,9 @@ export function isolateAgentInstance(prototype, threadId) {
|
|
|
90
90
|
if ("abortController" in withAbort) {
|
|
91
91
|
withAbort.abortController = new AbortController();
|
|
92
92
|
}
|
|
93
|
+
// From here on Channels calls the local AG-UI client API. The structural
|
|
94
|
+
// input contract above has checked every member Channels relies on without
|
|
95
|
+
// requiring the caller's AbstractAgent class identity to match ours.
|
|
93
96
|
return cloned;
|
|
94
97
|
}
|
|
95
98
|
/**
|
|
@@ -368,6 +371,9 @@ export function createChannel(opts) {
|
|
|
368
371
|
registerWaiter: (k, r) => waiters.set(k, r),
|
|
369
372
|
interruptHandlers,
|
|
370
373
|
state: backend,
|
|
374
|
+
// Tie the retained interrupt value's lifetime to the action that resumes
|
|
375
|
+
// it — same knob, so they cannot drift apart.
|
|
376
|
+
interruptRetentionMs: cfg.actionRetentionMs,
|
|
371
377
|
stateSchema: cfg.state,
|
|
372
378
|
transcripts,
|
|
373
379
|
message: extras?.message,
|
|
@@ -27,6 +27,14 @@ const __handlerTypeGuards = () => {
|
|
|
27
27
|
// @ts-expect-error 'nope' is not on the action value type
|
|
28
28
|
ctx.action.value?.nope;
|
|
29
29
|
});
|
|
30
|
+
// A clone method alone is not enough: Channels reads and mutates the full
|
|
31
|
+
// agent runtime surface while processing a turn.
|
|
32
|
+
createChannel({
|
|
33
|
+
identifyUser: "platform",
|
|
34
|
+
adapters: [new FakeAdapter()],
|
|
35
|
+
// @ts-expect-error incomplete agents must not satisfy the public boundary
|
|
36
|
+
agent: { clone: () => ({}) },
|
|
37
|
+
});
|
|
30
38
|
};
|
|
31
39
|
void __handlerTypeGuards;
|
|
32
40
|
/** Recursively find the first node of a given type in an IR tree. */
|
|
@@ -376,8 +376,16 @@ test("normal runs write no continuation state and one resume consumes once", asy
|
|
|
376
376
|
expect(consume).not.toHaveBeenCalled();
|
|
377
377
|
await turn("interrupt");
|
|
378
378
|
const actionId = firstActionId(adapter);
|
|
379
|
-
|
|
380
|
-
|
|
379
|
+
// Asserted by KEY, not by call count. An interrupt turn writes exactly one
|
|
380
|
+
// action snapshot — that is the invariant this test is about — plus the
|
|
381
|
+
// retained interrupt value that `resume` echoes back as
|
|
382
|
+
// `command.interruptEvent` (see interrupt-event-echo.test.tsx). A bare count
|
|
383
|
+
// conflates the two and breaks on bookkeeping that is not continuation state.
|
|
384
|
+
const writes = set.mock.calls.map((call) => String(call[0]));
|
|
385
|
+
expect(writes.filter((key) => key.startsWith("action:"))).toEqual([
|
|
386
|
+
`action:${actionId}`,
|
|
387
|
+
]);
|
|
388
|
+
expect(writes).toContain("interruptevent:thread-1");
|
|
381
389
|
expect(consume).not.toHaveBeenCalled();
|
|
382
390
|
const click = (eventId) => adapter.getSink().onInteraction({
|
|
383
391
|
id: actionId,
|
|
@@ -388,6 +396,11 @@ test("normal runs write no continuation state and one resume consumes once", asy
|
|
|
388
396
|
});
|
|
389
397
|
await click("bob-click");
|
|
390
398
|
await click("bob-click-redelivery");
|
|
391
|
-
|
|
392
|
-
|
|
399
|
+
// The load-bearing part: the ACTION is consumed exactly once across the click
|
|
400
|
+
// and its redelivery. Filtered by key for the same reason as above — the resume
|
|
401
|
+
// also consumes the retained interrupt value, which is a separate one-use item.
|
|
402
|
+
const consumed = consume.mock.calls.map((call) => String(call[0]));
|
|
403
|
+
expect(consumed.filter((key) => key.startsWith("action:"))).toEqual([
|
|
404
|
+
`action:${actionId}`,
|
|
405
|
+
]);
|
|
393
406
|
});
|
package/dist/identity.d.ts
CHANGED
|
@@ -31,6 +31,50 @@ export interface ChannelIdentityContext {
|
|
|
31
31
|
readonly raw: unknown;
|
|
32
32
|
readonly lookupProfile?: () => Promise<ProviderActor | undefined>;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Who is speaking this turn, as the agent receives it.
|
|
36
|
+
*
|
|
37
|
+
* Forwarded to the agent as `forwardedProps.channelActor` on every run of a
|
|
38
|
+
* turn — see {@link channelActorIdentity} for why it travels there and not on
|
|
39
|
+
* the user message.
|
|
40
|
+
*
|
|
41
|
+
* `id` is provider-scoped, not global: two platforms can hand out the same
|
|
42
|
+
* string for different people. An agent keying anything per person — a
|
|
43
|
+
* third-party account, a per-user credential, a rate limit — keys it on
|
|
44
|
+
* `platform` and `id` together, never `id` alone.
|
|
45
|
+
*
|
|
46
|
+
* `kind` and the display fields are provider-reported metadata. They are useful
|
|
47
|
+
* for addressing someone and useless for deciding what they may do.
|
|
48
|
+
*/
|
|
49
|
+
export interface ChannelActorIdentity {
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly kind: ProviderActor["kind"];
|
|
52
|
+
/** Source provider for this turn, e.g. `"slack"`. Namespaces `id`. */
|
|
53
|
+
readonly platform: string;
|
|
54
|
+
readonly name?: string;
|
|
55
|
+
readonly handle?: string;
|
|
56
|
+
readonly email?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The trusted actor for one turn, or `undefined` when the ingress named nobody.
|
|
60
|
+
*
|
|
61
|
+
* This exists because the obvious alternative is wrong. AG-UI messages carry an
|
|
62
|
+
* optional author, and putting the actor there would be a smaller change — but
|
|
63
|
+
* that field is part of the message list handed to a model provider, and
|
|
64
|
+
* providers validate it. OpenAI accepts only `[A-Za-z0-9_-]` in a message
|
|
65
|
+
* author; Teams actor ids contain a colon, and adapters bound an actor id at 512
|
|
66
|
+
* characters and nothing else. So an id that happens to fit one provider today
|
|
67
|
+
* is not a contract, and sanitizing it to fit is worse than failing: a mangled
|
|
68
|
+
* id still looks like an identity and silently answers as the wrong person.
|
|
69
|
+
*
|
|
70
|
+
* `forwardedProps` is per-run data that never enters the conversation, so no
|
|
71
|
+
* provider inspects it and the value stays exactly what the adapter reported.
|
|
72
|
+
*
|
|
73
|
+
* An actor with no id is dropped rather than forwarded as an empty string:
|
|
74
|
+
* ingress reports `id: ""` when the provider named nobody, and an agent must be
|
|
75
|
+
* able to tell "nobody" from "somebody" without string-comparing a sentinel.
|
|
76
|
+
*/
|
|
77
|
+
export declare function channelActorIdentity(actor: ProviderActor | undefined, platform: string): ChannelActorIdentity | undefined;
|
|
34
78
|
/** Explicit Channel identity strategy. */
|
|
35
79
|
export type ChannelIdentifyUser = "platform" | ((context: ChannelIdentityContext) => ApplicationUser | null | Promise<ApplicationUser | null>);
|
|
36
80
|
/** Identity facts supplied by an adapter alongside every ingress event. */
|
package/dist/identity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE9E,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wDAAwD;AACxD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,wDAAwD;AACxD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,4EAA4E;AAC5E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CACnE;AAED,0CAA0C;AAC1C,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,CAAC,CACC,OAAO,EAAE,sBAAsB,KAC5B,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;AAEnE,2EAA2E;AAC3E,MAAM,MAAM,sBAAsB,GAAG,IAAI,CACvC,sBAAsB,EACtB,UAAU,GAAG,OAAO,CACrB,CAAC;AAEF,mEAAmE;AACnE,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,8BAA8B;;CAQ5C;AAED,0EAA0E;AAC1E,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,IAAI,6BAA6B;IAC1C,SAAkB,KAAK,EAAE,OAAO,CAAC;gBAErB,KAAK,EAAE,OAAO;CAK3B;AAsBD,8EAA8E;AAC9E,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,mBAAmB,GAAG,SAAS,EAC7C,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAgBjC"}
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE9E,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wDAAwD;AACxD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,wDAAwD;AACxD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,4EAA4E;AAC5E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CACnE;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,QAAQ,EAAE,MAAM,GACf,oBAAoB,GAAG,SAAS,CAUlC;AAED,0CAA0C;AAC1C,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,CAAC,CACC,OAAO,EAAE,sBAAsB,KAC5B,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;AAEnE,2EAA2E;AAC3E,MAAM,MAAM,sBAAsB,GAAG,IAAI,CACvC,sBAAsB,EACtB,UAAU,GAAG,OAAO,CACrB,CAAC;AAEF,mEAAmE;AACnE,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,8BAA8B;;CAQ5C;AAED,0EAA0E;AAC1E,qBAAa,8BAA+B,SAAQ,KAAK;IACvD,QAAQ,CAAC,IAAI,6BAA6B;IAC1C,SAAkB,KAAK,EAAE,OAAO,CAAC;gBAErB,KAAK,EAAE,OAAO;CAK3B;AAsBD,8EAA8E;AAC9E,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,mBAAmB,GAAG,SAAS,EAC7C,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAgBjC"}
|
package/dist/identity.js
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The trusted actor for one turn, or `undefined` when the ingress named nobody.
|
|
3
|
+
*
|
|
4
|
+
* This exists because the obvious alternative is wrong. AG-UI messages carry an
|
|
5
|
+
* optional author, and putting the actor there would be a smaller change — but
|
|
6
|
+
* that field is part of the message list handed to a model provider, and
|
|
7
|
+
* providers validate it. OpenAI accepts only `[A-Za-z0-9_-]` in a message
|
|
8
|
+
* author; Teams actor ids contain a colon, and adapters bound an actor id at 512
|
|
9
|
+
* characters and nothing else. So an id that happens to fit one provider today
|
|
10
|
+
* is not a contract, and sanitizing it to fit is worse than failing: a mangled
|
|
11
|
+
* id still looks like an identity and silently answers as the wrong person.
|
|
12
|
+
*
|
|
13
|
+
* `forwardedProps` is per-run data that never enters the conversation, so no
|
|
14
|
+
* provider inspects it and the value stays exactly what the adapter reported.
|
|
15
|
+
*
|
|
16
|
+
* An actor with no id is dropped rather than forwarded as an empty string:
|
|
17
|
+
* ingress reports `id: ""` when the provider named nobody, and an agent must be
|
|
18
|
+
* able to tell "nobody" from "somebody" without string-comparing a sentinel.
|
|
19
|
+
*/
|
|
20
|
+
export function channelActorIdentity(actor, platform) {
|
|
21
|
+
if (!actor?.id)
|
|
22
|
+
return undefined;
|
|
23
|
+
return {
|
|
24
|
+
id: actor.id,
|
|
25
|
+
kind: actor.kind,
|
|
26
|
+
platform,
|
|
27
|
+
...(actor.name ? { name: actor.name } : {}),
|
|
28
|
+
...(actor.handle ? { handle: actor.handle } : {}),
|
|
29
|
+
...(actor.email ? { email: actor.email } : {}),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
1
32
|
/** Stable public failure for malformed custom identity results. */
|
|
2
33
|
export class ChannelIdentityResultError extends Error {
|
|
3
34
|
code = "channel_identity_invalid";
|
package/dist/identity.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect, test, vi } from "vitest";
|
|
2
|
-
import { ChannelIdentityResolutionError, ChannelIdentityResultError, resolveChannelUser, } from "./identity.js";
|
|
2
|
+
import { channelActorIdentity, ChannelIdentityResolutionError, ChannelIdentityResultError, resolveChannelUser, } from "./identity.js";
|
|
3
3
|
function context(kind = "human") {
|
|
4
4
|
return {
|
|
5
5
|
provider: "slack",
|
|
@@ -107,3 +107,30 @@ test("a failing lazy profile lookup cannot break platform identity", async () =>
|
|
|
107
107
|
await expect(resolveChannelUser("platform", identityContext)).resolves.toEqual({ id: "slack:T1:U1", name: "U1" });
|
|
108
108
|
expect(lookupProfile).not.toHaveBeenCalled();
|
|
109
109
|
});
|
|
110
|
+
test("channelActorIdentity names the actor and the platform that scopes them", () => {
|
|
111
|
+
expect(channelActorIdentity({ id: "U1", kind: "human", name: "Ada", handle: "ada", email: "a@b.c" }, "slack")).toEqual({
|
|
112
|
+
id: "U1",
|
|
113
|
+
kind: "human",
|
|
114
|
+
platform: "slack",
|
|
115
|
+
name: "Ada",
|
|
116
|
+
handle: "ada",
|
|
117
|
+
email: "a@b.c",
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
test("channelActorIdentity omits display fields the provider did not report", () => {
|
|
121
|
+
expect(channelActorIdentity({ id: "U1", kind: "human" }, "slack")).toEqual({
|
|
122
|
+
id: "U1",
|
|
123
|
+
kind: "human",
|
|
124
|
+
platform: "slack",
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
test("channelActorIdentity passes an id through unaltered", () => {
|
|
128
|
+
// A Teams id carries a colon, and adapters bound an actor id only by length.
|
|
129
|
+
// Reshaping it to suit a model provider's author charset would answer as
|
|
130
|
+
// somebody else, so nothing here rewrites it.
|
|
131
|
+
expect(channelActorIdentity({ id: "29:1a2b3c", kind: "human" }, "teams")?.id).toBe("29:1a2b3c");
|
|
132
|
+
});
|
|
133
|
+
test("channelActorIdentity reports nobody when the ingress named nobody", () => {
|
|
134
|
+
expect(channelActorIdentity({ id: "", kind: "unknown" }, "slack")).toBeUndefined();
|
|
135
|
+
expect(channelActorIdentity(undefined, "slack")).toBeUndefined();
|
|
136
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ export { HttpAgent } from "@ag-ui/client";
|
|
|
5
5
|
export type { Channel, CreateChannelOptions, ReplyContinuationOptions, ChannelHandler, WelcomeHandler, ThreadStartHandler, ReactionEvent, ReactionHandler, ModalSubmitEvent, ModalSubmitHandler, ModalCloseEvent, ModalCloseHandler, StoreConfig, LockConflictDecision, ChannelConcurrency, StatefulThread, ChannelComponent, ChannelComponentRegistration, } from "./create-channel.js";
|
|
6
6
|
export { defineChannelComponent } from "./channel-component.js";
|
|
7
7
|
export type { ChannelComponentDefinition, ChannelComponentPlatform, ChannelComponentRenderContext, } from "./channel-component.js";
|
|
8
|
-
export { ChannelIdentityResolutionError, ChannelIdentityResultError, resolveChannelUser, } from "./identity.js";
|
|
9
|
-
export type { ChannelConversation, ChannelEvent, ChannelIdentifyUser, ChannelIdentityContext, ChannelInstallation, ChannelTenant, IngressIdentityContext, } from "./identity.js";
|
|
8
|
+
export { channelActorIdentity, ChannelIdentityResolutionError, ChannelIdentityResultError, resolveChannelUser, } from "./identity.js";
|
|
9
|
+
export type { ChannelActorIdentity, ChannelConversation, ChannelEvent, ChannelIdentifyUser, ChannelIdentityContext, ChannelInstallation, ChannelTenant, IngressIdentityContext, } from "./identity.js";
|
|
10
10
|
export { Thread } from "./thread.js";
|
|
11
11
|
export type { ThreadDeps } from "./thread.js";
|
|
12
12
|
export type { PlatformAdapter, AdapterStartContext, RunRenderer, IngressSink, IncomingTurn, InteractionEvent, IncomingCommand, IncomingThreadStart, IncomingWelcome, IncomingReaction, IncomingModalSubmit, IncomingModalClose, ModalSubmitResult, SurfaceCapabilities, ReplyTarget, ConversationStore, AgentSession, CapturedToolCall, CapturedInterrupt, ChannelAgentLifecycleArgs, ChannelAgentLoopResult, CanonicalRunIdentity, UserQuery, NativePayload, } from "./platform-adapter.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export { sanitizeAgentEventStream } from "./sanitize-agent-events.js";
|
|
|
9
9
|
// wiring one up needs no second import (any `AbstractAgent` still works).
|
|
10
10
|
export { HttpAgent } from "@ag-ui/client";
|
|
11
11
|
export { defineChannelComponent } from "./channel-component.js";
|
|
12
|
-
export { ChannelIdentityResolutionError, ChannelIdentityResultError, resolveChannelUser, } from "./identity.js";
|
|
12
|
+
export { channelActorIdentity, ChannelIdentityResolutionError, ChannelIdentityResultError, resolveChannelUser, } from "./identity.js";
|
|
13
13
|
// Thread
|
|
14
14
|
export { Thread } from "./thread.js";
|
|
15
15
|
// Slash commands
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interrupt-event-echo.test.d.ts","sourceRoot":"","sources":["../src/interrupt-event-echo.test.tsx"],"names":[],"mappings":""}
|