@dudousxd/nestjs-agent-react 0.34.0 → 0.34.2
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/dist/index.cjs +155 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -14
- package/dist/index.d.ts +33 -14
- package/dist/index.js +155 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -390,18 +390,33 @@ declare function useAttachments(options?: UseAttachmentsOptions): AttachmentsSta
|
|
|
390
390
|
* What maps where (the inverse of the producer in `@adonis-agora/agent/ag-ui`):
|
|
391
391
|
* - `TEXT_MESSAGE_*` → `text`; `REASONING_MESSAGE_*` → `reasoning`; `STEP_*` → `step-start` /
|
|
392
392
|
* `step-finish`;
|
|
393
|
-
* - `TOOL_CALL_START` / `ARGS` / `END` → `tool-input-start` / `-delta` / `-available
|
|
394
|
-
* `
|
|
395
|
-
* `
|
|
393
|
+
* - `TOOL_CALL_START` / `ARGS` / `END` → `tool-input-start` / `-delta` / `-available`, with the
|
|
394
|
+
* `toolKind` and `parentId` from `metadata['agora.toolKind']` / `['agora.parentId']` (a call
|
|
395
|
+
* without them is a `read`); `TOOL_CALL_RESULT` → `tool-output` (or `tool-output-error` /
|
|
396
|
+
* `-denied`, from `metadata['agora.outcome']`);
|
|
396
397
|
* - `ACTIVITY_SNAPSHOT` / `ACTIVITY_DELTA` → a `ui` part named `AgUiActivity`, id
|
|
397
398
|
* `activity:<messageId>`, props `{ activityType, content }` — the whole content each time (the
|
|
398
399
|
* delta's JSON Patch applied here), so a repeat replaces the widget in place;
|
|
399
400
|
* - `RUN_ERROR` → the stream's `event: error`; `RUN_FINISHED` → `event: done` (a cancelled
|
|
400
|
-
* outcome writes `cancelled` first
|
|
401
|
-
* `
|
|
401
|
+
* outcome writes `cancelled` first). An interrupt outcome whose every interrupt this stream
|
|
402
|
+
* already showed (`agora.approval-requested` / `agora.elicitation`) ends the stream WITHOUT
|
|
403
|
+
* `done`: the run is parked, not over, so the transport re-attaches to it on the native route
|
|
404
|
+
* (`chat/:runId/stream?after=`) and the rest of the run — after the person decides through the
|
|
405
|
+
* native `tool-call` routes — streams into the same message. An interrupt nothing showed (another
|
|
406
|
+
* producer's) becomes a `ui` part named `AgUiInterrupt` carrying it, for the app to render;
|
|
407
|
+
* - the producer's SSE `id:` (the run's own sequence number, which this library's producer writes)
|
|
408
|
+
* is passed on as the cursor the transport re-attaches with; frames of a producer that numbers
|
|
409
|
+
* nothing carry no id, and the transport then does not try to re-attach;
|
|
402
410
|
* - `CUSTOM` events a producer of this family writes (`agora.ui`, `agora.title`, `agora.queue`,
|
|
403
|
-
* `agora.approval-requested` / `-settled`, `agora.run`) → the frames they
|
|
404
|
-
* `
|
|
411
|
+
* `agora.approval-requested` / `-settled`, `agora.elicitation`, `agora.run`) → the frames they
|
|
412
|
+
* stand for; `agora.step-usage` (right after a `STEP_FINISHED`) → that step's `usage`, `costUsd`
|
|
413
|
+
* and `reasoningMs` on its `step-finish`; `agora.action-proposal-decision` → the
|
|
414
|
+
* `data-proposal-decision` part a native decision answers with (`{ threadId, proposalDecision,
|
|
415
|
+
* text }`). Any other `CUSTOM` is ignored, as the protocol requires of a consumer that does not
|
|
416
|
+
* know it.
|
|
417
|
+
*
|
|
418
|
+
* And on the way in: the send's staged `attachments` (`{ mediaId }`) become `file` content parts
|
|
419
|
+
* the producer resolves for the caller, and `regenerate: true` rides `forwardedProps`.
|
|
405
420
|
*/
|
|
406
421
|
interface AgUiChatStreamOptions {
|
|
407
422
|
/** The producer's endpoint (`POST`, `RunAgentInput` in, `text/event-stream` out). */
|
|
@@ -411,16 +426,20 @@ interface AgUiChatStreamOptions {
|
|
|
411
426
|
/** Defaults to the global `fetch`, with `credentials: 'same-origin'`. */
|
|
412
427
|
fetch?: typeof fetch;
|
|
413
428
|
/**
|
|
414
|
-
* Shape `forwardedProps` from the send's body. Default: `{ pageContext, agent, model, persona,
|
|
415
|
-
* body, whichever are present.
|
|
429
|
+
* Shape `forwardedProps` from the send's body. Default: `{ pageContext, agent, model, persona,
|
|
430
|
+
* uiCapabilities, regenerate }` from the body, whichever are present.
|
|
416
431
|
*/
|
|
417
432
|
forwardedProps?: (body: Record<string, unknown>) => unknown;
|
|
418
433
|
/** Read the refusal of a non-2xx answer. Default: the JSON body's `message`, else the status. */
|
|
419
434
|
refusal?: (response: Response) => Promise<Error>;
|
|
420
435
|
/**
|
|
421
|
-
* The user message's `content` for the send. Default: the body's `message` as a string
|
|
422
|
-
*
|
|
423
|
-
*
|
|
436
|
+
* The user message's `content` for the send. Default: the body's `message` as a string — or,
|
|
437
|
+
* when the send carries staged `attachments` (`{ mediaId, contentType? }`, what the composer
|
|
438
|
+
* uploads), a `text` part followed by one `file` part per attachment
|
|
439
|
+
* (`source: { type: 'file', value: <mediaId>, provider: 'nestjs-agent' }`), which this library's
|
|
440
|
+
* producer resolves for the caller. Return your own list of AG-UI content parts to send inline
|
|
441
|
+
* bytes instead — `{ type: 'image' | 'document' | …, source: { type: 'data', value: <base64>,
|
|
442
|
+
* mimeType } }`.
|
|
424
443
|
*/
|
|
425
444
|
content?: (body: Record<string, unknown>) => string | AgUiContentPart[];
|
|
426
445
|
}
|
|
@@ -450,8 +469,8 @@ type AgUiContentPart = {
|
|
|
450
469
|
declare function agUiChatStream(request: ChatStreamRequest, options: AgUiChatStreamOptions): Promise<ChatStreamResponse>;
|
|
451
470
|
/**
|
|
452
471
|
* Re-frame an AG-UI event stream (SSE, one event per `data:`) in this library's stream protocol:
|
|
453
|
-
* `event: meta`,
|
|
454
|
-
* `event: error`. Exported for a backend that fetches the stream itself.
|
|
472
|
+
* `event: meta`, `data:` frames of {@link AgentStreamEvent} (numbered with the run's own sequence
|
|
473
|
+
* when the producer numbers its events), then `event: done` or `event: error`. Exported for a backend that fetches the stream itself.
|
|
455
474
|
*/
|
|
456
475
|
declare function reframeAgUiStream(source: ReadableStream<Uint8Array>, ids: {
|
|
457
476
|
threadId: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -390,18 +390,33 @@ declare function useAttachments(options?: UseAttachmentsOptions): AttachmentsSta
|
|
|
390
390
|
* What maps where (the inverse of the producer in `@adonis-agora/agent/ag-ui`):
|
|
391
391
|
* - `TEXT_MESSAGE_*` → `text`; `REASONING_MESSAGE_*` → `reasoning`; `STEP_*` → `step-start` /
|
|
392
392
|
* `step-finish`;
|
|
393
|
-
* - `TOOL_CALL_START` / `ARGS` / `END` → `tool-input-start` / `-delta` / `-available
|
|
394
|
-
* `
|
|
395
|
-
* `
|
|
393
|
+
* - `TOOL_CALL_START` / `ARGS` / `END` → `tool-input-start` / `-delta` / `-available`, with the
|
|
394
|
+
* `toolKind` and `parentId` from `metadata['agora.toolKind']` / `['agora.parentId']` (a call
|
|
395
|
+
* without them is a `read`); `TOOL_CALL_RESULT` → `tool-output` (or `tool-output-error` /
|
|
396
|
+
* `-denied`, from `metadata['agora.outcome']`);
|
|
396
397
|
* - `ACTIVITY_SNAPSHOT` / `ACTIVITY_DELTA` → a `ui` part named `AgUiActivity`, id
|
|
397
398
|
* `activity:<messageId>`, props `{ activityType, content }` — the whole content each time (the
|
|
398
399
|
* delta's JSON Patch applied here), so a repeat replaces the widget in place;
|
|
399
400
|
* - `RUN_ERROR` → the stream's `event: error`; `RUN_FINISHED` → `event: done` (a cancelled
|
|
400
|
-
* outcome writes `cancelled` first
|
|
401
|
-
* `
|
|
401
|
+
* outcome writes `cancelled` first). An interrupt outcome whose every interrupt this stream
|
|
402
|
+
* already showed (`agora.approval-requested` / `agora.elicitation`) ends the stream WITHOUT
|
|
403
|
+
* `done`: the run is parked, not over, so the transport re-attaches to it on the native route
|
|
404
|
+
* (`chat/:runId/stream?after=`) and the rest of the run — after the person decides through the
|
|
405
|
+
* native `tool-call` routes — streams into the same message. An interrupt nothing showed (another
|
|
406
|
+
* producer's) becomes a `ui` part named `AgUiInterrupt` carrying it, for the app to render;
|
|
407
|
+
* - the producer's SSE `id:` (the run's own sequence number, which this library's producer writes)
|
|
408
|
+
* is passed on as the cursor the transport re-attaches with; frames of a producer that numbers
|
|
409
|
+
* nothing carry no id, and the transport then does not try to re-attach;
|
|
402
410
|
* - `CUSTOM` events a producer of this family writes (`agora.ui`, `agora.title`, `agora.queue`,
|
|
403
|
-
* `agora.approval-requested` / `-settled`, `agora.run`) → the frames they
|
|
404
|
-
* `
|
|
411
|
+
* `agora.approval-requested` / `-settled`, `agora.elicitation`, `agora.run`) → the frames they
|
|
412
|
+
* stand for; `agora.step-usage` (right after a `STEP_FINISHED`) → that step's `usage`, `costUsd`
|
|
413
|
+
* and `reasoningMs` on its `step-finish`; `agora.action-proposal-decision` → the
|
|
414
|
+
* `data-proposal-decision` part a native decision answers with (`{ threadId, proposalDecision,
|
|
415
|
+
* text }`). Any other `CUSTOM` is ignored, as the protocol requires of a consumer that does not
|
|
416
|
+
* know it.
|
|
417
|
+
*
|
|
418
|
+
* And on the way in: the send's staged `attachments` (`{ mediaId }`) become `file` content parts
|
|
419
|
+
* the producer resolves for the caller, and `regenerate: true` rides `forwardedProps`.
|
|
405
420
|
*/
|
|
406
421
|
interface AgUiChatStreamOptions {
|
|
407
422
|
/** The producer's endpoint (`POST`, `RunAgentInput` in, `text/event-stream` out). */
|
|
@@ -411,16 +426,20 @@ interface AgUiChatStreamOptions {
|
|
|
411
426
|
/** Defaults to the global `fetch`, with `credentials: 'same-origin'`. */
|
|
412
427
|
fetch?: typeof fetch;
|
|
413
428
|
/**
|
|
414
|
-
* Shape `forwardedProps` from the send's body. Default: `{ pageContext, agent, model, persona,
|
|
415
|
-
* body, whichever are present.
|
|
429
|
+
* Shape `forwardedProps` from the send's body. Default: `{ pageContext, agent, model, persona,
|
|
430
|
+
* uiCapabilities, regenerate }` from the body, whichever are present.
|
|
416
431
|
*/
|
|
417
432
|
forwardedProps?: (body: Record<string, unknown>) => unknown;
|
|
418
433
|
/** Read the refusal of a non-2xx answer. Default: the JSON body's `message`, else the status. */
|
|
419
434
|
refusal?: (response: Response) => Promise<Error>;
|
|
420
435
|
/**
|
|
421
|
-
* The user message's `content` for the send. Default: the body's `message` as a string
|
|
422
|
-
*
|
|
423
|
-
*
|
|
436
|
+
* The user message's `content` for the send. Default: the body's `message` as a string — or,
|
|
437
|
+
* when the send carries staged `attachments` (`{ mediaId, contentType? }`, what the composer
|
|
438
|
+
* uploads), a `text` part followed by one `file` part per attachment
|
|
439
|
+
* (`source: { type: 'file', value: <mediaId>, provider: 'nestjs-agent' }`), which this library's
|
|
440
|
+
* producer resolves for the caller. Return your own list of AG-UI content parts to send inline
|
|
441
|
+
* bytes instead — `{ type: 'image' | 'document' | …, source: { type: 'data', value: <base64>,
|
|
442
|
+
* mimeType } }`.
|
|
424
443
|
*/
|
|
425
444
|
content?: (body: Record<string, unknown>) => string | AgUiContentPart[];
|
|
426
445
|
}
|
|
@@ -450,8 +469,8 @@ type AgUiContentPart = {
|
|
|
450
469
|
declare function agUiChatStream(request: ChatStreamRequest, options: AgUiChatStreamOptions): Promise<ChatStreamResponse>;
|
|
451
470
|
/**
|
|
452
471
|
* Re-frame an AG-UI event stream (SSE, one event per `data:`) in this library's stream protocol:
|
|
453
|
-
* `event: meta`,
|
|
454
|
-
* `event: error`. Exported for a backend that fetches the stream itself.
|
|
472
|
+
* `event: meta`, `data:` frames of {@link AgentStreamEvent} (numbered with the run's own sequence
|
|
473
|
+
* when the producer numbers its events), then `event: done` or `event: error`. Exported for a backend that fetches the stream itself.
|
|
455
474
|
*/
|
|
456
475
|
declare function reframeAgUiStream(source: ReadableStream<Uint8Array>, ids: {
|
|
457
476
|
threadId: string;
|
package/dist/index.js
CHANGED
|
@@ -948,7 +948,10 @@ var AgentChatTransport = class {
|
|
|
948
948
|
forwardAsData(event, true);
|
|
949
949
|
break;
|
|
950
950
|
default:
|
|
951
|
-
forwardAsData(
|
|
951
|
+
forwardAsData(
|
|
952
|
+
event,
|
|
953
|
+
event.kind === "proposal-decision"
|
|
954
|
+
);
|
|
952
955
|
break;
|
|
953
956
|
}
|
|
954
957
|
}
|
|
@@ -1969,8 +1972,33 @@ function defaultForwardedProps(body) {
|
|
|
1969
1972
|
for (const key of ["pageContext", "agent", "model", "persona", "uiCapabilities"]) {
|
|
1970
1973
|
if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
|
|
1971
1974
|
}
|
|
1975
|
+
if (body.regenerate === true) out.regenerate = true;
|
|
1972
1976
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
1973
1977
|
}
|
|
1978
|
+
var MEDIA_PROVIDER = "nestjs-agent";
|
|
1979
|
+
function partTypeFor(contentType) {
|
|
1980
|
+
const major = contentType?.split("/")[0]?.toLowerCase();
|
|
1981
|
+
return major === "image" || major === "audio" || major === "video" ? major : "document";
|
|
1982
|
+
}
|
|
1983
|
+
function defaultContent(body, message) {
|
|
1984
|
+
const attachments = Array.isArray(body.attachments) ? body.attachments : [];
|
|
1985
|
+
const files = [];
|
|
1986
|
+
for (const attachment of attachments) {
|
|
1987
|
+
if (!isRecord2(attachment) || typeof attachment.mediaId !== "string") continue;
|
|
1988
|
+
const contentType = typeof attachment.contentType === "string" ? attachment.contentType : void 0;
|
|
1989
|
+
files.push({
|
|
1990
|
+
type: partTypeFor(contentType),
|
|
1991
|
+
source: {
|
|
1992
|
+
type: "file",
|
|
1993
|
+
value: attachment.mediaId,
|
|
1994
|
+
provider: MEDIA_PROVIDER,
|
|
1995
|
+
...contentType !== void 0 ? { mimeType: contentType } : {}
|
|
1996
|
+
}
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1999
|
+
if (files.length === 0) return message;
|
|
2000
|
+
return [...message.length > 0 ? [{ type: "text", text: message }] : [], ...files];
|
|
2001
|
+
}
|
|
1974
2002
|
async function agUiChatStream(request, options) {
|
|
1975
2003
|
const body = request.body;
|
|
1976
2004
|
const threadId = typeof body.threadId === "string" ? body.threadId : newId();
|
|
@@ -1980,7 +2008,13 @@ async function agUiChatStream(request, options) {
|
|
|
1980
2008
|
threadId,
|
|
1981
2009
|
runId: newId(),
|
|
1982
2010
|
protocolVersion: "1.0",
|
|
1983
|
-
messages: [
|
|
2011
|
+
messages: [
|
|
2012
|
+
{
|
|
2013
|
+
id: newId(),
|
|
2014
|
+
role: "user",
|
|
2015
|
+
content: options.content?.(body) ?? defaultContent(body, message)
|
|
2016
|
+
}
|
|
2017
|
+
],
|
|
1984
2018
|
...forwarded !== void 0 ? { forwardedProps: forwarded } : {}
|
|
1985
2019
|
};
|
|
1986
2020
|
const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
@@ -2017,6 +2051,8 @@ function reframeAgUiStream(source, ids) {
|
|
|
2017
2051
|
for (; ; ) {
|
|
2018
2052
|
const { value, done } = await reader.read();
|
|
2019
2053
|
if (done) {
|
|
2054
|
+
const rest = reframer.flush();
|
|
2055
|
+
if (rest.length > 0) controller.enqueue(encoder.encode(rest));
|
|
2020
2056
|
controller.close();
|
|
2021
2057
|
return;
|
|
2022
2058
|
}
|
|
@@ -2027,7 +2063,10 @@ function reframeAgUiStream(source, ids) {
|
|
|
2027
2063
|
const block = buffer.slice(0, separator);
|
|
2028
2064
|
buffer = buffer.slice(separator + 2);
|
|
2029
2065
|
separator = buffer.indexOf("\n\n");
|
|
2030
|
-
const
|
|
2066
|
+
const lines = block.split("\n");
|
|
2067
|
+
const idLine = lines.find((line) => line.startsWith("id:"));
|
|
2068
|
+
const id = idLine === void 0 ? void 0 : Number(idLine.slice(3).trim());
|
|
2069
|
+
const data = lines.filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
|
|
2031
2070
|
if (data.length === 0) continue;
|
|
2032
2071
|
let event;
|
|
2033
2072
|
try {
|
|
@@ -2036,7 +2075,10 @@ function reframeAgUiStream(source, ids) {
|
|
|
2036
2075
|
continue;
|
|
2037
2076
|
}
|
|
2038
2077
|
if (isRecord2(event) && typeof event.type === "string") {
|
|
2039
|
-
out += reframer.push(
|
|
2078
|
+
out += reframer.push(
|
|
2079
|
+
event,
|
|
2080
|
+
id !== void 0 && Number.isSafeInteger(id) && id > 0 ? id : void 0
|
|
2081
|
+
);
|
|
2040
2082
|
}
|
|
2041
2083
|
if (reframer.closed) break;
|
|
2042
2084
|
}
|
|
@@ -2056,21 +2098,55 @@ function reframeAgUiStream(source, ids) {
|
|
|
2056
2098
|
}
|
|
2057
2099
|
function createReframer(threadId) {
|
|
2058
2100
|
const activities = /* @__PURE__ */ new Map();
|
|
2059
|
-
let seq = 0;
|
|
2060
2101
|
let metaSent = false;
|
|
2061
2102
|
const tools = /* @__PURE__ */ new Map();
|
|
2103
|
+
let pendingStep;
|
|
2104
|
+
const encodeFrame = (streamEvent) => `data: ${JSON.stringify(streamEvent)}
|
|
2105
|
+
|
|
2106
|
+
`;
|
|
2107
|
+
const flushStep = () => {
|
|
2108
|
+
if (pendingStep === void 0) return "";
|
|
2109
|
+
const step = pendingStep;
|
|
2110
|
+
pendingStep = void 0;
|
|
2111
|
+
return encodeFrame(step);
|
|
2112
|
+
};
|
|
2113
|
+
let current;
|
|
2114
|
+
let written;
|
|
2115
|
+
const cursor = () => {
|
|
2116
|
+
if (current === void 0 || current === written) return "";
|
|
2117
|
+
written = current;
|
|
2118
|
+
return `${flushStep()}id: ${current}
|
|
2119
|
+
|
|
2120
|
+
`;
|
|
2121
|
+
};
|
|
2122
|
+
const shown = /* @__PURE__ */ new Set();
|
|
2123
|
+
let decision;
|
|
2062
2124
|
const state = {
|
|
2063
2125
|
closed: false,
|
|
2064
|
-
|
|
2126
|
+
flush() {
|
|
2127
|
+
return state.closed ? "" : `${flushStep()}${cursor()}`;
|
|
2128
|
+
},
|
|
2129
|
+
push(event, id) {
|
|
2065
2130
|
if (state.closed) return "";
|
|
2066
2131
|
let out = "";
|
|
2132
|
+
if (id !== void 0) {
|
|
2133
|
+
if (current !== void 0 && id > current) out += cursor();
|
|
2134
|
+
current = id;
|
|
2135
|
+
}
|
|
2067
2136
|
const frame = (streamEvent) => {
|
|
2068
|
-
|
|
2069
|
-
out += `id: ${seq}
|
|
2070
|
-
data: ${JSON.stringify(streamEvent)}
|
|
2071
|
-
|
|
2072
|
-
`;
|
|
2137
|
+
out += encodeFrame(streamEvent);
|
|
2073
2138
|
};
|
|
2139
|
+
if (event.type === "CUSTOM" && event.name === "agora.step-usage" && pendingStep !== void 0 && isRecord2(event.value)) {
|
|
2140
|
+
const value = event.value;
|
|
2141
|
+
if (isRecord2(value.usage)) pendingStep.usage = value.usage;
|
|
2142
|
+
if (typeof value.costUsd === "number" || value.costUsd === null) {
|
|
2143
|
+
pendingStep.costUsd = value.costUsd;
|
|
2144
|
+
}
|
|
2145
|
+
if (typeof value.reasoningMs === "number") pendingStep.reasoningMs = value.reasoningMs;
|
|
2146
|
+
out += flushStep();
|
|
2147
|
+
return out;
|
|
2148
|
+
}
|
|
2149
|
+
out += flushStep();
|
|
2074
2150
|
const meta = (runId, thread) => {
|
|
2075
2151
|
if (metaSent) return;
|
|
2076
2152
|
metaSent = true;
|
|
@@ -2100,9 +2176,24 @@ data: ${JSON.stringify({
|
|
|
2100
2176
|
frame({ kind: "title", title: value.title });
|
|
2101
2177
|
} else if (event.name === "agora.queue") frame({ kind: "queue", ...value });
|
|
2102
2178
|
else if (event.name === "agora.approval-requested") {
|
|
2179
|
+
if (typeof value.id === "string") shown.add(value.id);
|
|
2103
2180
|
frame({ ...value, kind: "approval-requested" });
|
|
2104
2181
|
} else if (event.name === "agora.approval-settled") {
|
|
2105
2182
|
frame({ ...value, kind: "approval-settled" });
|
|
2183
|
+
} else if (event.name === "agora.elicitation" && typeof value.id === "string" && isRecord2(value.request) && Array.isArray(value.request.questions)) {
|
|
2184
|
+
shown.add(value.id);
|
|
2185
|
+
if (typeof value.request.id === "string") shown.add(value.request.id);
|
|
2186
|
+
frame({
|
|
2187
|
+
kind: "elicitation",
|
|
2188
|
+
id: value.id,
|
|
2189
|
+
request: value.request
|
|
2190
|
+
});
|
|
2191
|
+
} else if (event.name === "agora.action-proposal-decision") {
|
|
2192
|
+
decision = {
|
|
2193
|
+
threadId: value.threadId,
|
|
2194
|
+
proposalDecision: value.proposalDecision,
|
|
2195
|
+
text: ""
|
|
2196
|
+
};
|
|
2106
2197
|
}
|
|
2107
2198
|
return out;
|
|
2108
2199
|
}
|
|
@@ -2112,6 +2203,9 @@ data: ${JSON.stringify({
|
|
|
2112
2203
|
switch (event.type) {
|
|
2113
2204
|
case "TEXT_MESSAGE_CONTENT":
|
|
2114
2205
|
case "TEXT_MESSAGE_CHUNK":
|
|
2206
|
+
if (decision !== void 0 && typeof event.delta === "string") {
|
|
2207
|
+
decision.text += event.delta;
|
|
2208
|
+
}
|
|
2115
2209
|
if (typeof event.delta === "string" && event.delta.length > 0) {
|
|
2116
2210
|
frame({ kind: "text", text: event.delta });
|
|
2117
2211
|
}
|
|
@@ -2126,20 +2220,34 @@ data: ${JSON.stringify({
|
|
|
2126
2220
|
frame({ kind: "step-start" });
|
|
2127
2221
|
break;
|
|
2128
2222
|
case "STEP_FINISHED":
|
|
2129
|
-
|
|
2223
|
+
pendingStep = { kind: "step-finish" };
|
|
2130
2224
|
break;
|
|
2131
2225
|
case "TOOL_CALL_START":
|
|
2132
2226
|
case "TOOL_CALL_CHUNK": {
|
|
2133
|
-
const
|
|
2134
|
-
if (
|
|
2135
|
-
if (!tools.has(
|
|
2227
|
+
const id2 = String(event.toolCallId ?? "");
|
|
2228
|
+
if (id2 === "") break;
|
|
2229
|
+
if (!tools.has(id2)) {
|
|
2136
2230
|
const name = typeof event.toolCallName === "string" ? event.toolCallName : "";
|
|
2137
|
-
|
|
2138
|
-
|
|
2231
|
+
const metadata = isRecord2(event.metadata) ? event.metadata : {};
|
|
2232
|
+
const toolKind2 = metadata["agora.toolKind"] === "action" ? "action" : "read";
|
|
2233
|
+
const parentId = typeof metadata["agora.parentId"] === "string" ? metadata["agora.parentId"] : void 0;
|
|
2234
|
+
tools.set(id2, {
|
|
2235
|
+
name,
|
|
2236
|
+
args: "",
|
|
2237
|
+
toolKind: toolKind2,
|
|
2238
|
+
...parentId !== void 0 ? { parentId } : {}
|
|
2239
|
+
});
|
|
2240
|
+
frame({
|
|
2241
|
+
kind: "tool-input-start",
|
|
2242
|
+
id: id2,
|
|
2243
|
+
name,
|
|
2244
|
+
toolKind: toolKind2,
|
|
2245
|
+
...parentId !== void 0 ? { parentId } : {}
|
|
2246
|
+
});
|
|
2139
2247
|
}
|
|
2140
2248
|
if (event.type === "TOOL_CALL_CHUNK" && typeof event.delta === "string") {
|
|
2141
|
-
tools.get(
|
|
2142
|
-
frame({ kind: "tool-input-delta", id, delta: event.delta });
|
|
2249
|
+
tools.get(id2).args += event.delta;
|
|
2250
|
+
frame({ kind: "tool-input-delta", id: id2, delta: event.delta });
|
|
2143
2251
|
}
|
|
2144
2252
|
break;
|
|
2145
2253
|
}
|
|
@@ -2151,25 +2259,26 @@ data: ${JSON.stringify({
|
|
|
2151
2259
|
break;
|
|
2152
2260
|
}
|
|
2153
2261
|
case "TOOL_CALL_END": {
|
|
2154
|
-
const
|
|
2155
|
-
const call = tools.get(
|
|
2262
|
+
const id2 = String(event.toolCallId);
|
|
2263
|
+
const call = tools.get(id2);
|
|
2156
2264
|
if (call === void 0) break;
|
|
2157
2265
|
frame({
|
|
2158
2266
|
kind: "tool-input-available",
|
|
2159
|
-
id,
|
|
2267
|
+
id: id2,
|
|
2160
2268
|
name: call.name,
|
|
2161
2269
|
input: parseJson(call.args, {}),
|
|
2162
|
-
toolKind:
|
|
2270
|
+
toolKind: call.toolKind,
|
|
2271
|
+
...call.parentId !== void 0 ? { parentId: call.parentId } : {}
|
|
2163
2272
|
});
|
|
2164
2273
|
break;
|
|
2165
2274
|
}
|
|
2166
2275
|
case "TOOL_CALL_RESULT": {
|
|
2167
|
-
const
|
|
2276
|
+
const id2 = String(event.toolCallId);
|
|
2168
2277
|
const content = contentText(event.content);
|
|
2169
2278
|
const outcome = isRecord2(event.metadata) ? event.metadata["agora.outcome"] : void 0;
|
|
2170
|
-
if (outcome === "error") frame({ kind: "tool-output-error", id, error: content });
|
|
2171
|
-
else if (outcome === "denied") frame({ kind: "tool-output-denied", id, reason: content });
|
|
2172
|
-
else frame({ kind: "tool-output", id, output: parseJson(content, content) });
|
|
2279
|
+
if (outcome === "error") frame({ kind: "tool-output-error", id: id2, error: content });
|
|
2280
|
+
else if (outcome === "denied") frame({ kind: "tool-output-denied", id: id2, reason: content });
|
|
2281
|
+
else frame({ kind: "tool-output", id: id2, output: parseJson(content, content) });
|
|
2173
2282
|
break;
|
|
2174
2283
|
}
|
|
2175
2284
|
case "ACTIVITY_SNAPSHOT":
|
|
@@ -2208,15 +2317,26 @@ data: ${JSON.stringify({
|
|
|
2208
2317
|
break;
|
|
2209
2318
|
case "RUN_FINISHED": {
|
|
2210
2319
|
const outcome = isRecord2(event.outcome) ? event.outcome : void 0;
|
|
2320
|
+
if (decision !== void 0) {
|
|
2321
|
+
frame({ kind: "proposal-decision", ...decision });
|
|
2322
|
+
decision = void 0;
|
|
2323
|
+
}
|
|
2211
2324
|
if (outcome?.type === "cancelled") frame({ kind: "cancelled" });
|
|
2212
2325
|
if (outcome?.type === "interrupt" && Array.isArray(outcome.interrupts)) {
|
|
2326
|
+
const unseen = outcome.interrupts.filter((interrupt) => !isShown(interrupt, shown));
|
|
2327
|
+
if (unseen.length === 0) {
|
|
2328
|
+
out += cursor();
|
|
2329
|
+
state.closed = true;
|
|
2330
|
+
break;
|
|
2331
|
+
}
|
|
2213
2332
|
frame({
|
|
2214
2333
|
kind: "ui",
|
|
2215
2334
|
id: `ag-ui:interrupt:${String(event.runId ?? "")}`,
|
|
2216
2335
|
component: "AgUiInterrupt",
|
|
2217
|
-
props: { interrupts:
|
|
2336
|
+
props: { interrupts: unseen }
|
|
2218
2337
|
});
|
|
2219
2338
|
}
|
|
2339
|
+
out += cursor();
|
|
2220
2340
|
state.closed = true;
|
|
2221
2341
|
out += "event: done\ndata: {}\n\n";
|
|
2222
2342
|
break;
|
|
@@ -2236,6 +2356,13 @@ data: ${JSON.stringify({
|
|
|
2236
2356
|
let pendingStart;
|
|
2237
2357
|
return state;
|
|
2238
2358
|
}
|
|
2359
|
+
function isShown(interrupt, shown) {
|
|
2360
|
+
if (!isRecord2(interrupt)) return false;
|
|
2361
|
+
if (typeof interrupt.toolCallId === "string" && shown.has(interrupt.toolCallId)) return true;
|
|
2362
|
+
const metadata = isRecord2(interrupt.metadata) ? interrupt.metadata : void 0;
|
|
2363
|
+
const request = isRecord2(metadata?.["agora.request"]) ? metadata["agora.request"] : void 0;
|
|
2364
|
+
return typeof request?.id === "string" && shown.has(request.id);
|
|
2365
|
+
}
|
|
2239
2366
|
function parseJson(text, fallback2) {
|
|
2240
2367
|
if (text.trim().length === 0) return fallback2;
|
|
2241
2368
|
try {
|