@downcity/agent 1.1.23 → 1.1.25
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/bin/index.d.ts +2 -3
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js.map +1 -1
- package/bin/runtime/server/http/control/SessionRoutes.d.ts.map +1 -1
- package/bin/runtime/server/http/control/SessionRoutes.js +0 -27
- package/bin/runtime/server/http/control/SessionRoutes.js.map +1 -1
- package/bin/sdk/SessionEventMapper.d.ts +4 -4
- package/bin/sdk/SessionEventMapper.d.ts.map +1 -1
- package/bin/sdk/SessionEventMapper.js +1 -1
- package/bin/types/sdk/{AgentUiChunkEvent.d.ts → InternalUiChunkEvent.d.ts} +6 -6
- package/bin/types/sdk/InternalUiChunkEvent.d.ts.map +1 -0
- package/bin/types/sdk/InternalUiChunkEvent.js +9 -0
- package/bin/types/sdk/InternalUiChunkEvent.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +2 -7
- package/src/runtime/server/http/control/SessionRoutes.ts +0 -27
- package/src/sdk/SessionEventMapper.ts +4 -4
- package/src/types/sdk/{AgentUiChunkEvent.ts → InternalUiChunkEvent.ts} +5 -5
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/runtime/server/http/control/StreamBySession.d.ts +0 -22
- package/bin/runtime/server/http/control/StreamBySession.d.ts.map +0 -1
- package/bin/runtime/server/http/control/StreamBySession.js +0 -135
- package/bin/runtime/server/http/control/StreamBySession.js.map +0 -1
- package/bin/types/sdk/AgentUiChunkEvent.d.ts.map +0 -1
- package/bin/types/sdk/AgentUiChunkEvent.js +0 -9
- package/bin/types/sdk/AgentUiChunkEvent.js.map +0 -1
- package/src/runtime/server/http/control/StreamBySession.ts +0 -198
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Control session 增量执行 helper。
|
|
3
|
-
*
|
|
4
|
-
* 关键点(中文)
|
|
5
|
-
* - 仅用于单 agent control API 的本地 session 增量返回。
|
|
6
|
-
* - chatKey 命中的平台 chat 队列仍保持原有入队语义,不在这里伪造“流式完成”。
|
|
7
|
-
* - 输出协议使用内部 `AgentUiChunkEvent` 的 NDJSON 事件行,便于 CLI 直接消费。
|
|
8
|
-
*/
|
|
9
|
-
import type { AgentContext } from "../../../../core/AgentContextTypes.js";
|
|
10
|
-
import type { AgentRuntime } from "../../../../core/AgentCoreTypes.js";
|
|
11
|
-
import type { ControlSessionExecuteAttachmentInput } from "../../../../runtime/server/http/control/types/ControlSessionExecute.js";
|
|
12
|
-
/**
|
|
13
|
-
* 为指定 session 创建流式执行响应。
|
|
14
|
-
*/
|
|
15
|
-
export declare function createControlSessionStreamResponse(params: {
|
|
16
|
-
agentState: AgentRuntime;
|
|
17
|
-
executionContext: AgentContext;
|
|
18
|
-
sessionId: string;
|
|
19
|
-
instructions: string;
|
|
20
|
-
attachments?: ControlSessionExecuteAttachmentInput[];
|
|
21
|
-
}): Promise<Response>;
|
|
22
|
-
//# sourceMappingURL=StreamBySession.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StreamBySession.d.ts","sourceRoot":"","sources":["../../../../../src/runtime/server/http/control/StreamBySession.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EACV,oCAAoC,EACrC,MAAM,8DAA8D,CAAC;AAkEtE;;GAEG;AACH,wBAAsB,kCAAkC,CAAC,MAAM,EAAE;IAC/D,UAAU,EAAE,YAAY,CAAC;IACzB,gBAAgB,EAAE,YAAY,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,oCAAoC,EAAE,CAAC;CACtD,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6GpB"}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Control session 增量执行 helper。
|
|
3
|
-
*
|
|
4
|
-
* 关键点(中文)
|
|
5
|
-
* - 仅用于单 agent control API 的本地 session 增量返回。
|
|
6
|
-
* - chatKey 命中的平台 chat 队列仍保持原有入队语义,不在这里伪造“流式完成”。
|
|
7
|
-
* - 输出协议使用内部 `AgentUiChunkEvent` 的 NDJSON 事件行,便于 CLI 直接消费。
|
|
8
|
-
*/
|
|
9
|
-
import { buildExecuteInputText } from "../../../../runtime/server/http/control/Helpers.js";
|
|
10
|
-
import { drainDeferredPersistedUserMessages } from "../../../../session/SessionRunScope.js";
|
|
11
|
-
import { mapUiMessageChunkToAgentEvent } from "../../../../sdk/SessionEventMapper.js";
|
|
12
|
-
import { resolveDispatchTargetByChatKey } from "../../../../service/builtins/chat/runtime/ChatkeySend.js";
|
|
13
|
-
import { pickLastSuccessfulChatSendText, resolveAssistantMessageForPersistence, } from "../../../../service/builtins/chat/runtime/UserVisibleText.js";
|
|
14
|
-
const NDJSON_CONTENT_TYPE = "application/x-ndjson; charset=utf-8";
|
|
15
|
-
function encodeNdjsonLine(encoder, value) {
|
|
16
|
-
return encoder.encode(`${JSON.stringify(value)}\n`);
|
|
17
|
-
}
|
|
18
|
-
function resolveStreamEventFromUiChunk(params) {
|
|
19
|
-
const { chunk, toolNameByCallId } = params;
|
|
20
|
-
if (chunk.type === "tool-input-start") {
|
|
21
|
-
toolNameByCallId.set(chunk.toolCallId, chunk.toolName);
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
const event = mapUiMessageChunkToAgentEvent(chunk);
|
|
25
|
-
if (!event)
|
|
26
|
-
return null;
|
|
27
|
-
if (event.type === "tool-call" || event.type === "tool-error") {
|
|
28
|
-
toolNameByCallId.set(event.toolCallId, event.toolName);
|
|
29
|
-
}
|
|
30
|
-
if ((event.type === "tool-result" || event.type === "tool-error") &&
|
|
31
|
-
event.toolName === "unknown") {
|
|
32
|
-
const toolName = toolNameByCallId.get(event.toolCallId);
|
|
33
|
-
return toolName ? { ...event, toolName } : event;
|
|
34
|
-
}
|
|
35
|
-
return event;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* 为指定 session 创建流式执行响应。
|
|
39
|
-
*/
|
|
40
|
-
export async function createControlSessionStreamResponse(params) {
|
|
41
|
-
const sessionId = String(params.sessionId || "").trim();
|
|
42
|
-
const instructions = String(params.instructions || "").trim();
|
|
43
|
-
if (!sessionId) {
|
|
44
|
-
return Response.json({ success: false, error: "Missing sessionId" }, { status: 400 });
|
|
45
|
-
}
|
|
46
|
-
if (!instructions) {
|
|
47
|
-
return Response.json({ success: false, error: "Missing instructions" }, { status: 400 });
|
|
48
|
-
}
|
|
49
|
-
const executeInput = await buildExecuteInputText({
|
|
50
|
-
projectRoot: params.agentState.rootPath,
|
|
51
|
-
sessionId,
|
|
52
|
-
instructions,
|
|
53
|
-
attachments: params.attachments,
|
|
54
|
-
});
|
|
55
|
-
const dispatchTarget = await resolveDispatchTargetByChatKey({
|
|
56
|
-
context: params.executionContext,
|
|
57
|
-
chatKey: sessionId,
|
|
58
|
-
});
|
|
59
|
-
if (dispatchTarget) {
|
|
60
|
-
return Response.json({
|
|
61
|
-
success: false,
|
|
62
|
-
error: "Streaming execute does not support queued chat sessions. Use the non-stream execute API for chatKey routes.",
|
|
63
|
-
}, { status: 409 });
|
|
64
|
-
}
|
|
65
|
-
const session = params.agentState.getSession(sessionId);
|
|
66
|
-
const encoder = new TextEncoder();
|
|
67
|
-
const stream = new ReadableStream({
|
|
68
|
-
start(controller) {
|
|
69
|
-
void (async () => {
|
|
70
|
-
const toolNameByCallId = new Map();
|
|
71
|
-
const pushEvent = (event) => {
|
|
72
|
-
controller.enqueue(encodeNdjsonLine(encoder, event));
|
|
73
|
-
};
|
|
74
|
-
try {
|
|
75
|
-
await session.appendUserMessage({
|
|
76
|
-
text: executeInput,
|
|
77
|
-
});
|
|
78
|
-
const result = await session.execute({
|
|
79
|
-
query: executeInput,
|
|
80
|
-
onUiMessageChunkCallback: async (chunk) => {
|
|
81
|
-
const event = resolveStreamEventFromUiChunk({
|
|
82
|
-
chunk,
|
|
83
|
-
toolNameByCallId,
|
|
84
|
-
});
|
|
85
|
-
if (!event)
|
|
86
|
-
return;
|
|
87
|
-
pushEvent(event);
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
const userVisible = pickLastSuccessfulChatSendText(result.assistantMessage).trim();
|
|
91
|
-
try {
|
|
92
|
-
const messageForPersistence = resolveAssistantMessageForPersistence(result.assistantMessage);
|
|
93
|
-
if (messageForPersistence) {
|
|
94
|
-
await session.appendAssistantMessage({
|
|
95
|
-
message: messageForPersistence,
|
|
96
|
-
fallbackText: userVisible,
|
|
97
|
-
extra: {
|
|
98
|
-
via: "tui_session_stream",
|
|
99
|
-
note: "assistant_message_missing",
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
const deferredInjectedMessages = drainDeferredPersistedUserMessages(sessionId);
|
|
104
|
-
for (const message of deferredInjectedMessages) {
|
|
105
|
-
await session.appendUserMessage({
|
|
106
|
-
message,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
// ignore persistence follow-up errors after stream completion
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
pushEvent({
|
|
116
|
-
type: "error",
|
|
117
|
-
error: error instanceof Error ? error.message : String(error),
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
controller.close();
|
|
122
|
-
}
|
|
123
|
-
})();
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
return new Response(stream, {
|
|
127
|
-
status: 200,
|
|
128
|
-
headers: {
|
|
129
|
-
"Content-Type": NDJSON_CONTENT_TYPE,
|
|
130
|
-
"Cache-Control": "no-cache, no-transform",
|
|
131
|
-
"X-Accel-Buffering": "no",
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
//# sourceMappingURL=StreamBySession.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StreamBySession.js","sourceRoot":"","sources":["../../../../../src/runtime/server/http/control/StreamBySession.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AgentUiChunkEvent.d.ts","sourceRoot":"","sources":["../../../src/types/sdk/AgentUiChunkEvent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB;IACE;;OAEG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE;;OAEG;IACH,IAAI,EAAE,iBAAiB,CAAC;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;CACjB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IACpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,EAAE,SAAS,CAAC;CACnB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IACE;;OAEG;IACH,IAAI,EAAE,QAAQ,CAAC;IACf;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AgentUiChunkEvent.js","sourceRoot":"","sources":["../../../src/types/sdk/AgentUiChunkEvent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Control session 增量执行 helper。
|
|
3
|
-
*
|
|
4
|
-
* 关键点(中文)
|
|
5
|
-
* - 仅用于单 agent control API 的本地 session 增量返回。
|
|
6
|
-
* - chatKey 命中的平台 chat 队列仍保持原有入队语义,不在这里伪造“流式完成”。
|
|
7
|
-
* - 输出协议使用内部 `AgentUiChunkEvent` 的 NDJSON 事件行,便于 CLI 直接消费。
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { AgentContext, SessionPort } from "@/core/AgentContextTypes.js";
|
|
11
|
-
import type { AgentRuntime } from "@/core/AgentCoreTypes.js";
|
|
12
|
-
import type {
|
|
13
|
-
ControlSessionExecuteAttachmentInput,
|
|
14
|
-
} from "@/runtime/server/http/control/types/ControlSessionExecute.js";
|
|
15
|
-
import { buildExecuteInputText } from "@/runtime/server/http/control/Helpers.js";
|
|
16
|
-
import { drainDeferredPersistedUserMessages } from "@session/SessionRunScope.js";
|
|
17
|
-
import { mapUiMessageChunkToAgentEvent } from "@/sdk/SessionEventMapper.js";
|
|
18
|
-
import type { AgentUiChunkEvent } from "@/types/sdk/AgentUiChunkEvent.js";
|
|
19
|
-
import type {
|
|
20
|
-
SessionRunResult,
|
|
21
|
-
SessionUiMessageChunkCallback,
|
|
22
|
-
} from "@/session/types/SessionRun.js";
|
|
23
|
-
import { resolveDispatchTargetByChatKey } from "@/service/builtins/chat/runtime/ChatkeySend.js";
|
|
24
|
-
import {
|
|
25
|
-
pickLastSuccessfulChatSendText,
|
|
26
|
-
resolveAssistantMessageForPersistence,
|
|
27
|
-
} from "@/service/builtins/chat/runtime/UserVisibleText.js";
|
|
28
|
-
|
|
29
|
-
type StreamableSessionPort = SessionPort & {
|
|
30
|
-
/**
|
|
31
|
-
* 流式执行当前 session。
|
|
32
|
-
*
|
|
33
|
-
* 说明(中文)
|
|
34
|
-
* - `SessionPort` 对外接口当前未显式暴露 `onUiMessageChunkCallback`,
|
|
35
|
-
* 但本地 executor 已支持该回调,这里按本地 control runtime 语义做窄化使用。
|
|
36
|
-
*/
|
|
37
|
-
execute(params: {
|
|
38
|
-
query: string;
|
|
39
|
-
onUiMessageChunkCallback?: SessionUiMessageChunkCallback;
|
|
40
|
-
}): Promise<SessionRunResult>;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const NDJSON_CONTENT_TYPE = "application/x-ndjson; charset=utf-8";
|
|
44
|
-
|
|
45
|
-
function encodeNdjsonLine(
|
|
46
|
-
encoder: TextEncoder,
|
|
47
|
-
value: AgentUiChunkEvent,
|
|
48
|
-
): Uint8Array {
|
|
49
|
-
return encoder.encode(`${JSON.stringify(value)}\n`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function resolveStreamEventFromUiChunk(params: {
|
|
53
|
-
chunk: Parameters<NonNullable<SessionUiMessageChunkCallback>>[0];
|
|
54
|
-
toolNameByCallId: Map<string, string>;
|
|
55
|
-
}): AgentUiChunkEvent | null {
|
|
56
|
-
const { chunk, toolNameByCallId } = params;
|
|
57
|
-
if (chunk.type === "tool-input-start") {
|
|
58
|
-
toolNameByCallId.set(chunk.toolCallId, chunk.toolName);
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const event = mapUiMessageChunkToAgentEvent(chunk);
|
|
63
|
-
if (!event) return null;
|
|
64
|
-
|
|
65
|
-
if (event.type === "tool-call" || event.type === "tool-error") {
|
|
66
|
-
toolNameByCallId.set(event.toolCallId, event.toolName);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
(event.type === "tool-result" || event.type === "tool-error") &&
|
|
71
|
-
event.toolName === "unknown"
|
|
72
|
-
) {
|
|
73
|
-
const toolName = toolNameByCallId.get(event.toolCallId);
|
|
74
|
-
return toolName ? { ...event, toolName } : event;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return event;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 为指定 session 创建流式执行响应。
|
|
82
|
-
*/
|
|
83
|
-
export async function createControlSessionStreamResponse(params: {
|
|
84
|
-
agentState: AgentRuntime;
|
|
85
|
-
executionContext: AgentContext;
|
|
86
|
-
sessionId: string;
|
|
87
|
-
instructions: string;
|
|
88
|
-
attachments?: ControlSessionExecuteAttachmentInput[];
|
|
89
|
-
}): Promise<Response> {
|
|
90
|
-
const sessionId = String(params.sessionId || "").trim();
|
|
91
|
-
const instructions = String(params.instructions || "").trim();
|
|
92
|
-
if (!sessionId) {
|
|
93
|
-
return Response.json({ success: false, error: "Missing sessionId" }, { status: 400 });
|
|
94
|
-
}
|
|
95
|
-
if (!instructions) {
|
|
96
|
-
return Response.json({ success: false, error: "Missing instructions" }, { status: 400 });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const executeInput = await buildExecuteInputText({
|
|
100
|
-
projectRoot: params.agentState.rootPath,
|
|
101
|
-
sessionId,
|
|
102
|
-
instructions,
|
|
103
|
-
attachments: params.attachments,
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
const dispatchTarget = await resolveDispatchTargetByChatKey({
|
|
107
|
-
context: params.executionContext,
|
|
108
|
-
chatKey: sessionId,
|
|
109
|
-
});
|
|
110
|
-
if (dispatchTarget) {
|
|
111
|
-
return Response.json(
|
|
112
|
-
{
|
|
113
|
-
success: false,
|
|
114
|
-
error:
|
|
115
|
-
"Streaming execute does not support queued chat sessions. Use the non-stream execute API for chatKey routes.",
|
|
116
|
-
},
|
|
117
|
-
{ status: 409 },
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const session = params.agentState.getSession(sessionId) as StreamableSessionPort;
|
|
122
|
-
const encoder = new TextEncoder();
|
|
123
|
-
|
|
124
|
-
const stream = new ReadableStream<Uint8Array>({
|
|
125
|
-
start(controller) {
|
|
126
|
-
void (async () => {
|
|
127
|
-
const toolNameByCallId = new Map<string, string>();
|
|
128
|
-
|
|
129
|
-
const pushEvent = (event: AgentUiChunkEvent): void => {
|
|
130
|
-
controller.enqueue(encodeNdjsonLine(encoder, event));
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
await session.appendUserMessage({
|
|
135
|
-
text: executeInput,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
const result = await session.execute({
|
|
139
|
-
query: executeInput,
|
|
140
|
-
onUiMessageChunkCallback: async (chunk) => {
|
|
141
|
-
const event = resolveStreamEventFromUiChunk({
|
|
142
|
-
chunk,
|
|
143
|
-
toolNameByCallId,
|
|
144
|
-
});
|
|
145
|
-
if (!event) return;
|
|
146
|
-
pushEvent(event);
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
const userVisible = pickLastSuccessfulChatSendText(
|
|
151
|
-
result.assistantMessage,
|
|
152
|
-
).trim();
|
|
153
|
-
try {
|
|
154
|
-
const messageForPersistence = resolveAssistantMessageForPersistence(
|
|
155
|
-
result.assistantMessage,
|
|
156
|
-
);
|
|
157
|
-
if (messageForPersistence) {
|
|
158
|
-
await session.appendAssistantMessage({
|
|
159
|
-
message: messageForPersistence,
|
|
160
|
-
fallbackText: userVisible,
|
|
161
|
-
extra: {
|
|
162
|
-
via: "tui_session_stream",
|
|
163
|
-
note: "assistant_message_missing",
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
const deferredInjectedMessages = drainDeferredPersistedUserMessages(
|
|
168
|
-
sessionId,
|
|
169
|
-
);
|
|
170
|
-
for (const message of deferredInjectedMessages) {
|
|
171
|
-
await session.appendUserMessage({
|
|
172
|
-
message,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
} catch {
|
|
176
|
-
// ignore persistence follow-up errors after stream completion
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
pushEvent({
|
|
180
|
-
type: "error",
|
|
181
|
-
error: error instanceof Error ? error.message : String(error),
|
|
182
|
-
});
|
|
183
|
-
} finally {
|
|
184
|
-
controller.close();
|
|
185
|
-
}
|
|
186
|
-
})();
|
|
187
|
-
},
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
return new Response(stream, {
|
|
191
|
-
status: 200,
|
|
192
|
-
headers: {
|
|
193
|
-
"Content-Type": NDJSON_CONTENT_TYPE,
|
|
194
|
-
"Cache-Control": "no-cache, no-transform",
|
|
195
|
-
"X-Accel-Buffering": "no",
|
|
196
|
-
},
|
|
197
|
-
});
|
|
198
|
-
}
|