@kddd/artinet-sdk
Version:
TypeScript SDK for the Agent2Agent (A2A) Protocol
134 lines • 5.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupSseStream = setupSseStream;
exports.sendSSEEvent = sendSSEEvent;
exports.sendSSEError = sendSSEError;
exports.processTaskStream = processTaskStream;
const state_js_1 = require("../../server/lib/state.js");
const errors_js_1 = require("../../utils/common/errors.js");
const utils_js_1 = require("../../utils/common/utils.js");
const log_js_1 = require("../../utils/logging/log.js");
const constants_js_1 = require("../../utils/common/constants.js");
/**
* Sets up a Server-Sent Events stream with appropriate headers
* and initializes tracking for the stream.
*
* @param res The Express Response object
* @param taskId The task ID to associate with this stream
* @param reqId The request ID for acknowledgment
* @param initialStatus Optional initial status to send
* @param addStreamMethod Function to add stream to tracking
* @param sendSseMethod Function to send SSE events
*/
function setupSseStream(res, taskId, initialStatus, addStreamMethod) {
// Set up SSE stream headers
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
// Track this stream for potential cancellation if tracking method provided
if (addStreamMethod) {
addStreamMethod(taskId, res);
}
// Send initial status if provided
if (initialStatus) {
sendSSEEvent(res, initialStatus);
}
}
/**
* Sends a Server-Sent Event with task data.
* @param res The Express Response object
* @param reqId The request ID
* @param eventData The event data to send
*/
function sendSSEEvent(res, update) {
if (!res.writable) {
return;
}
const response = {
jsonrpc: "2.0",
id: update.id,
result: update,
};
res.write(`data: ${JSON.stringify(response)}\n\n`);
}
/**
* Sends a Server-Sent Event with error data.
* @param res The Express Response object
* @param reqId The request ID
* @param error The error to send
*/
function sendSSEError(res, error) {
if (!res.writable) {
return;
}
const response = {
jsonrpc: "2.0",
error: error,
};
res.write(`data: ${JSON.stringify(response)}\n\n`);
}
/**
* Processes a task stream, handling generator yields and sending SSE events.
* @param req The request object
* @param res The response object
* @param taskId The task ID
* @param context The task context
* @param initialData The initial task data
*/
async function processTaskStream(taskStore, taskHandler, res, taskId, context, initialData, onCancel, onEnd) {
let currentData = initialData;
const generator = taskHandler(context);
try {
for await (const yieldValue of generator) {
if (context.isCancelled()) {
await onCancel(currentData, res);
return;
}
currentData = await (0, state_js_1.updateState)(taskStore, currentData, yieldValue);
context.task = currentData.task;
if ((0, utils_js_1.isTaskStatusUpdate)(yieldValue)) {
sendSSEEvent(res, {
id: taskId,
status: currentData.task.status,
final: constants_js_1.FINAL_STATES.includes(currentData.task.status.state),
});
}
else if ((0, utils_js_1.isArtifactUpdate)(yieldValue)) {
const artifactIndex = currentData.task.artifacts?.findIndex((a) => a.name && a.name === yieldValue.name) ??
yieldValue.index ??
-1;
if (artifactIndex >= 0 &&
currentData.task.artifacts &&
artifactIndex < currentData.task.artifacts.length) {
sendSSEEvent(res, {
id: taskId,
artifact: currentData.task.artifacts[artifactIndex],
final: constants_js_1.FINAL_STATES.includes(currentData.task.status.state),
});
}
}
}
}
catch (error) {
try {
const failedUpdate = (0, errors_js_1.FAILED_UPDATE)(error instanceof Error ? error.message : String(error));
currentData = await (0, state_js_1.updateState)(taskStore, currentData, failedUpdate);
sendSSEEvent(res, {
id: taskId,
status: currentData.task.status,
});
}
catch (saveError) {
(0, log_js_1.logError)("A2AServer", "Failed to save error state for streaming task", saveError, { taskId, originalError: error });
}
sendSSEError(res, (0, errors_js_1.INTERNAL_ERROR)(`Task execution error: ${error instanceof Error ? error.message : String(error)}`));
}
finally {
onEnd(taskId, res);
if (!res.writableEnded) {
res.write("event: close\ndata: {}\n\n");
res.end();
}
}
}
//# sourceMappingURL=stream.js.map