agents
Version:
A home for your AI agents
148 lines (147 loc) • 4.47 kB
JavaScript
//#region src/experimental/channels/web/protocol.ts
/**
* The header carrying a connection's WebIdentity from the gateway to the
* agent. The gateway always sets it, so a client cannot supply its own; an
* agent must not take WebSocket upgrades from any other route.
*/
const WEB_IDENTITY_HEADER = "x-channels-identity";
/**
* Parse a text frame. Returns undefined for anything that is not a Channels
* frame, so the socket's other protocols keep working.
*/
function parseClientFrame(text) {
let frame;
try {
frame = JSON.parse(text);
} catch {
return;
}
if (!isObject(frame) || typeof frame.type !== "string") return void 0;
if (frame.type === "channels:subscribe") {
const { responseId, from } = frame;
if (typeof responseId !== "string") return { invalid: "responseId" };
if (from !== void 0 && !Number.isInteger(from)) return { invalid: "from" };
return {
type: "channels:subscribe",
responseId,
...typeof from === "number" && { from }
};
}
if (frame.type === "channels:list-conversations") return isId(frame.requestId) ? {
type: "channels:list-conversations",
requestId: frame.requestId
} : { invalid: "requestId" };
if (frame.type !== "channels:event") return void 0;
const event = frame.event;
const eventId = isObject(event) ? event.eventId : void 0;
if (!isObject(event) || !isId(eventId)) return { invalid: "eventId" };
const parsed = parseEvent(event, eventId);
return typeof parsed === "string" ? {
invalid: parsed,
eventId
} : {
type: "channels:event",
event: parsed
};
}
function isObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isId(value) {
return typeof value === "string" && value.length > 0;
}
/** The event, or the name of the first invalid field. */
function parseEvent(event, eventId) {
switch (event.type) {
case "message": {
const message = event.message;
if (!isObject(message) || !isId(message.id)) return "message.id";
if (message.role !== "user") return "message.role";
const parts = message.parts;
if (!Array.isArray(parts) || !parts.every(isPart)) return "message.parts";
return {
type: "message",
eventId,
message: {
id: message.id,
role: "user",
parts,
...isObject(message.metadata) && { metadata: message.metadata }
},
...clientTools(event.clientTools)
};
}
case "tool-result": {
const { turnId, toolCallId, result } = event;
if (!isId(turnId)) return "turnId";
if (!isId(toolCallId)) return "toolCallId";
if (!isObject(result) || typeof result.ok !== "boolean") return "result";
return {
type: "tool-result",
eventId,
turnId,
toolCallId,
result: result.ok ? {
ok: true,
output: result.output ?? null
} : {
ok: false,
...typeof result.errorText === "string" && { errorText: result.errorText }
},
...clientTools(event.clientTools)
};
}
case "approval-response": {
const { turnId, approvalId, approved, reason } = event;
if (!isId(turnId)) return "turnId";
if (!isId(approvalId)) return "approvalId";
if (typeof approved !== "boolean") return "approved";
return {
type: "approval-response",
eventId,
turnId,
approvalId,
approved,
...typeof reason === "string" && { reason }
};
}
case "cancel": return isId(event.turnId) ? {
type: "cancel",
eventId,
turnId: event.turnId
} : "turnId";
case "conversation-create":
case "conversation-fork": return {
type: event.type,
eventId
};
case "conversation-reset":
if (event.handoff !== void 0 && typeof event.handoff !== "string") return "handoff";
return {
type: "conversation-reset",
eventId,
...event.handoff && { handoff: event.handoff }
};
default: return "type";
}
}
function isPart(part) {
return isObject(part) && typeof part.type === "string";
}
/** Keeps tools with a name, dropping a schema that is not an object. */
function clientTools(value) {
if (!Array.isArray(value)) return {};
const tools = [];
for (const tool of value) {
if (!isObject(tool) || !isId(tool.name)) continue;
tools.push({
name: tool.name,
...typeof tool.description === "string" && { description: tool.description },
...isObject(tool.inputSchema) && { inputSchema: tool.inputSchema }
});
}
return { clientTools: tools };
}
//#endregion
export { parseClientFrame as n, WEB_IDENTITY_HEADER as t };
//# sourceMappingURL=protocol-y2sSY584.js.map