bs-agent 0.0.24 → 0.0.26
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 +93 -15
- package/dist/{agent-Dr1JI3mA.d.cts → agent-D9xuE8wR.d.cts} +29 -4
- package/dist/{agent-Dr1JI3mA.d.ts → agent-D9xuE8wR.d.ts} +29 -4
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js.map +1 -1
- package/dist/react/index.cjs +63 -78
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +9 -6
- package/dist/react/index.d.ts +9 -6
- package/dist/react/index.js +63 -78
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/stream.ts","../../src/core/session.ts","../../src/core/agent.ts","../../src/core/index.ts"],"sourcesContent":["import type { StreamEvent, StreamOptions, SessionId } from \"./types\";\n\n/** Safely parse a value as JSON if it's a string, otherwise return as-is. */\nfunction tryParseJSON(value: unknown): any {\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n }\n return value;\n}\n\n/**\n * Fatal error — will NOT be retried.\n */\nclass FatalStreamError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = \"FatalStreamError\";\n }\n}\n\n/**\n * Opens an SSE connection to the BuildShip agent endpoint using native\n * `fetch` + `ReadableStream`, parses events, and dispatches to the\n * appropriate callbacks.\n *\n * Zero runtime dependencies — works in both browser and Node.js.\n *\n * @internal\n */\nexport async function executeStream(options: StreamOptions): Promise<void> {\n const {\n url,\n body,\n headers,\n callbacks,\n clientTools,\n signal,\n onSessionId,\n onPaused,\n onAutoResume,\n onResponse,\n } = options;\n\n let fullText = \"\";\n\n // Track pending auto-resume operations so we don't call onComplete prematurely\n const pendingAutoResumes: Promise<{ callId: string; result: unknown } | null>[] = [];\n\n // ── Make the request ────────────────────────────────────────────────\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n ...headers,\n },\n body: JSON.stringify(body),\n signal,\n });\n\n // ── Extract session ID and name from response headers ──────────────\n const sessionId = response.headers.get(\"X-BuildShip-Agent-Session-ID\");\n if (sessionId && onSessionId) {\n const sessionName = response.headers.get(\"X-BuildShip-Agent-Session-Name\") || undefined;\n onSessionId(sessionId as SessionId, sessionName);\n }\n\n // Expose the raw Response object\n onResponse?.(response);\n\n // ── Handle HTTP errors ─────────────────────────────────────────────\n if (!response.ok) {\n let errorBody = \"\";\n try {\n errorBody = await response.text();\n } catch {\n // ignore\n }\n const error = new FatalStreamError(\n `HTTP ${response.status}: ${errorBody || response.statusText}`,\n response.status,\n );\n callbacks.onError?.(error);\n throw error;\n }\n\n // ── Read the SSE stream ────────────────────────────────────────────\n if (!response.body) {\n callbacks.onComplete?.(fullText);\n return;\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop() || \"\";\n\n for (const part of parts) {\n const trimmedPart = part.trim();\n if (!trimmedPart) continue;\n\n // Extract the data field from SSE format\n let jsonStr = \"\";\n for (const line of trimmedPart.split(\"\\n\")) {\n if (line.startsWith(\"data: \")) {\n jsonStr += line.slice(6);\n } else if (line.startsWith(\"data:\")) {\n jsonStr += line.slice(5);\n }\n }\n\n jsonStr = jsonStr.trim();\n if (!jsonStr) continue;\n\n let raw: any;\n try {\n raw = JSON.parse(jsonStr);\n } catch {\n // Skip malformed events\n continue;\n }\n\n // Normalize backend event type names (llm_text_delta → text_delta, etc.)\n const streamEvent = normalizeEvent(raw) as StreamEvent;\n\n handleEvent(\n streamEvent,\n fullText,\n callbacks,\n clientTools,\n onPaused,\n onAutoResume,\n pendingAutoResumes,\n );\n\n // Accumulate text\n if (streamEvent.type === \"text_delta\") {\n fullText += streamEvent.data;\n }\n }\n }\n\n // Process any remaining data in buffer\n if (buffer.trim()) {\n let jsonStr = \"\";\n for (const line of buffer.trim().split(\"\\n\")) {\n if (line.startsWith(\"data: \")) {\n jsonStr += line.slice(6);\n } else if (line.startsWith(\"data:\")) {\n jsonStr += line.slice(5);\n }\n }\n\n jsonStr = jsonStr.trim();\n if (jsonStr) {\n try {\n const raw = JSON.parse(jsonStr);\n const streamEvent = normalizeEvent(raw) as StreamEvent;\n handleEvent(\n streamEvent,\n fullText,\n callbacks,\n clientTools,\n onPaused,\n onAutoResume,\n pendingAutoResumes,\n );\n if (streamEvent.type === \"text_delta\") {\n fullText += streamEvent.data;\n }\n } catch {\n // Skip malformed trailing data\n }\n }\n }\n } catch (err) {\n // AbortError — re-throw\n if (err instanceof Error && err.name === \"AbortError\") {\n throw err;\n }\n\n const error = err instanceof Error ? err : new Error(String(err));\n callbacks.onError?.(error);\n throw error;\n }\n\n // Wait for any pending auto-resume handlers before signaling completion\n if (pendingAutoResumes.length > 0) {\n const handlerResults = await Promise.allSettled(pendingAutoResumes);\n for (const settled of handlerResults) {\n if (settled.status === \"fulfilled\" && settled.value) {\n const { callId, result } = settled.value;\n await onAutoResume?.(callId, result);\n }\n }\n }\n\n callbacks.onComplete?.(fullText);\n}\n\n/**\n * Normalize backend event type names.\n * The backend sends `llm_text_delta` / `llm_reasoning_delta` but the SDK\n * exposes them as `text_delta` / `reasoning_delta`.\n * @internal\n */\nfunction normalizeEvent(raw: any): any {\n const typeMap: Record<string, string> = {\n llm_text_delta: \"text_delta\",\n llm_reasoning_delta: \"reasoning_delta\",\n };\n if (raw && typeof raw.type === \"string\" && typeMap[raw.type]) {\n raw.type = typeMap[raw.type];\n }\n return raw;\n}\n\n/**\n * Dispatch a parsed stream event to the appropriate callbacks.\n * @internal\n */\nfunction handleEvent(\n event: StreamEvent,\n _fullText: string,\n callbacks: StreamOptions[\"callbacks\"],\n clientTools: StreamOptions[\"clientTools\"],\n onPaused: StreamOptions[\"onPaused\"],\n onAutoResume: StreamOptions[\"onAutoResume\"],\n pendingAutoResumes: Promise<{ callId: string; result: unknown } | null>[],\n): void {\n // Notify raw event consumers\n callbacks.onEvent?.(event);\n\n switch (event.type) {\n case \"text_delta\": {\n callbacks.onText?.(event.data);\n break;\n }\n\n case \"reasoning_delta\": {\n callbacks.onReasoning?.(event.data.delta, event.data.index);\n break;\n }\n\n case \"agent_handoff\": {\n callbacks.onAgentHandoff?.(event.data.agentName);\n break;\n }\n\n case \"tool_call_start\": {\n const { callId, toolName, toolType, inputs: rawInputs, paused } = event.data;\n // Backend sends toolCall.arguments as a JSON string — parse it\n const inputs = tryParseJSON(rawInputs);\n\n // Notify callback\n callbacks.onToolStart?.(toolName, toolType);\n\n // Handle client tools\n if (toolType === \"client\") {\n const tool = clientTools.get(toolName);\n if (tool) {\n if (paused && tool.handler) {\n // Blocking tool with handler → auto-execute and resume\n const handlerPromise = (async (): Promise<{\n callId: string;\n result: unknown;\n } | null> => {\n try {\n const result = await tool.handler!(inputs);\n\n // Synthesize a tool_call_end event for local observers (like debug panels)\n // since the backend only emits for server-side executed tools\n callbacks.onEvent?.({\n type: \"tool_call_end\",\n data: {\n callId,\n toolName,\n toolType: \"client\",\n result,\n },\n meta: event.meta,\n });\n\n return { callId, result };\n } catch (error) {\n // If handler fails, still call onPaused so user can decide\n callbacks.onPaused?.(toolName, inputs);\n onPaused?.({ callId, toolName, args: inputs });\n return null;\n }\n })();\n pendingAutoResumes.push(handlerPromise);\n } else if (paused) {\n // Blocking tool without handler → pause for user\n callbacks.onPaused?.(toolName, inputs);\n onPaused?.({ callId, toolName, args: inputs });\n } else if (tool.handler) {\n // Fire-and-forget tool with handler\n try {\n tool.handler(inputs);\n } catch {\n // Swallow errors on fire-and-forget\n }\n }\n } else if (paused) {\n // No registered tool but paused — notify user\n callbacks.onPaused?.(toolName, inputs);\n onPaused?.({ callId, toolName, args: inputs });\n }\n }\n break;\n }\n\n case \"tool_call_end\": {\n const { toolName, result, error } = event.data;\n callbacks.onToolEnd?.(toolName, result, error);\n break;\n }\n\n case \"run_error\": {\n const { message, code } = event.data;\n const error = new Error(message);\n if (code != null) (error as any).code = code;\n callbacks.onError?.(error);\n break;\n }\n }\n}\n","import type {\n SessionId,\n StreamCallbacks,\n PausedToolInfo,\n ExecuteRequestBody,\n ExecuteOptions,\n} from \"./types\";\nimport type { BuildShipAgent } from \"./agent\";\nimport { executeStream } from \"./stream\";\nimport { toJSONSchema, type ZodSchema } from \"zod\";\n\n/**\n * Represents a conversation session with a BuildShip agent.\n *\n * Sessions maintain history across multiple turns and support\n * pause/resume for blocking client tools.\n */\nexport class AgentSession {\n /** @internal */ private _agent: BuildShipAgent;\n /** @internal */ private _sessionId: SessionId | undefined;\n /** @internal */ private _paused = false;\n /** @internal */ private _pausedToolInfo: PausedToolInfo | null = null;\n /** @internal */ private _abortController: AbortController | null = null;\n\n /** @internal */\n constructor(agent: BuildShipAgent, sessionId?: SessionId) {\n this._agent = agent;\n this._sessionId = sessionId;\n }\n\n // ─── Public API ────────────────────────────────────────────────────\n\n /**\n * Send a message in this session.\n *\n * @param message - The message to send\n * @param callbacks - Event handlers for the stream\n * @param callbacks - Event handlers for the stream\n * @param options - Optional settings like context, headers, or body\n * @returns This session (for chaining)\n */\n async execute(\n message: string,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n this._paused = false;\n this._pausedToolInfo = null;\n\n const body: ExecuteRequestBody = {\n ...(options?.body || {}),\n input: message,\n stream: true,\n };\n\n // Attach context as top-level properties if provided\n if (options?.context) {\n Object.assign(body, { context: options.context });\n }\n\n // Include client tool definitions\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n body.clientTools = clientToolDefs;\n }\n\n await this._run(body, callbacks, options);\n return this;\n }\n\n /**\n * Resume a paused session with a tool result.\n *\n * @param result - The result to send back to the agent\n * @param callbacks - Event handlers for the resumed stream\n * @param options - Optional settings like headers or body\n * @returns This session (for chaining)\n */\n async resume(\n result: any,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n if (!this._paused || !this._pausedToolInfo) {\n throw new Error(\"AgentSession.resume(): session is not paused. Check isPaused() first.\");\n }\n\n const body: ExecuteRequestBody = {\n ...(options?.body || {}),\n stream: true,\n toolCallResult: {\n callId: this._pausedToolInfo.callId,\n result,\n },\n };\n\n // Attach context if provided\n if (options?.context) {\n Object.assign(body, { context: options.context });\n }\n\n // Include client tool definitions for resume requests too\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n body.clientTools = clientToolDefs;\n }\n\n this._paused = false;\n this._pausedToolInfo = null;\n\n await this._run(body, callbacks, options);\n return this;\n }\n\n /**\n * Resume a session with an explicit tool call ID and result.\n *\n * Unlike `resume()`, this does NOT require the session to be in a paused state,\n * making it suitable for external resume flows (e.g. React widget submissions)\n * where the session object may have been re-created.\n *\n * @param callId - The tool call ID to resume\n * @param result - The result to send back to the agent\n * @param callbacks - Event handlers for the resumed stream\n * @param options - Optional settings like headers or body\n * @returns This session (for chaining)\n */\n async resumeWithCallId(\n callId: string,\n result: any,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n const body: ExecuteRequestBody = {\n ...(options?.body || {}),\n stream: true,\n toolCallResult: { callId, result },\n };\n\n // Attach context if provided\n if (options?.context) {\n Object.assign(body, { context: options.context });\n }\n\n // Include client tool definitions for resume requests too\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n body.clientTools = clientToolDefs;\n }\n\n // Clear any stale pause state\n this._paused = false;\n this._pausedToolInfo = null;\n\n await this._run(body, callbacks, options);\n return this;\n }\n\n /**\n * Check if this session is waiting for a tool result.\n */\n isPaused(): boolean {\n return this._paused;\n }\n\n /**\n * Get information about the paused tool call.\n * Returns `null` if the session is not paused.\n */\n getPausedTool(): PausedToolInfo | null {\n return this._pausedToolInfo;\n }\n\n /**\n * Get the session ID.\n * May be `undefined` if the session hasn't executed yet.\n */\n getSessionId(): SessionId {\n if (!this._sessionId) {\n throw new Error(\n \"AgentSession.getSessionId(): session ID not yet available. Call execute() first.\",\n );\n }\n return this._sessionId;\n }\n\n /**\n * Cancel the current streaming operation.\n */\n abort(): void {\n this._abortController?.abort();\n this._abortController = null;\n }\n\n // ─── Private helpers ───────────────────────────────────────────────\n\n /** @internal */\n private async _run(\n body: ExecuteRequestBody,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<void> {\n // Create a fresh abort controller for this run\n this._abortController = new AbortController();\n\n const baseHeaders = this._agent._buildHeaders(this._sessionId);\n const mergedHeaders = { ...baseHeaders, ...(options?.headers || {}) };\n\n await executeStream({\n url: this._agent._url,\n body,\n headers: mergedHeaders,\n callbacks,\n clientTools: this._agent._clientTools,\n signal: this._abortController.signal,\n\n onSessionId: (id, name) => {\n this._sessionId = id;\n options?.onSessionId?.(id, name);\n },\n\n onPaused: (info) => {\n this._paused = true;\n this._pausedToolInfo = info;\n },\n\n onAutoResume: async (callId, result) => {\n // Auto-resume: send the tool result back immediately\n const resumeBody: ExecuteRequestBody = {\n ...(options?.body || {}),\n stream: true,\n toolCallResult: { callId, result },\n };\n\n // Carry context forward from the original execute options\n if (options?.context) {\n Object.assign(resumeBody, { context: options.context });\n }\n\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n resumeBody.clientTools = clientToolDefs;\n }\n\n await this._run(resumeBody, callbacks, options);\n },\n });\n }\n\n /** @internal */\n private _getClientToolDefs() {\n const defs: ExecuteRequestBody[\"clientTools\"] = [];\n for (const tool of this._agent._clientTools.values()) {\n defs.push({\n name: tool.name,\n description: tool.description,\n parameters: resolveParameters(tool.parameters),\n await: tool.await,\n });\n }\n return defs;\n }\n}\n\n/**\n * Convert tool parameters to a JSON Schema object.\n * - If it's a Zod schema, uses Zod's built-in `toJSONSchema` to convert.\n * - Always ensures `additionalProperties: false` is set (required by the backend).\n * - Always ensures `required` includes every key in `properties` (Gemini requirement).\n * @internal\n */\nfunction resolveParameters(params: any): Record<string, any> {\n let schema: Record<string, any>;\n\n // Detect Zod schema: ZodType instances have a `_def` property\n if (params && typeof params === \"object\" && \"_def\" in params) {\n schema = toJSONSchema(params as ZodSchema) as Record<string, any>;\n // Remove $schema key if present\n delete schema.$schema;\n } else {\n schema = { ...params };\n }\n\n if (schema.type === \"object\") {\n // Backend requires additionalProperties: false\n schema.additionalProperties = false;\n\n // Gemini requires `required` to include every key in `properties`\n if (schema.properties) {\n schema.required = Object.keys(schema.properties);\n }\n }\n\n return schema;\n}\n","import type { AgentConfig, ClientTool, ExecuteOptions, SessionId, StreamCallbacks } from \"./types\";\nimport { AgentSession } from \"./session\";\n\nconst DEFAULT_BASE_URL = \"https://api.buildship.run\";\n\n/**\n * Main entry point for interacting with a BuildShip agent.\n *\n * @example\n * ```ts\n * import { BuildShipAgent } from \"buildship-agent-sdk/core\";\n *\n * const agent = new BuildShipAgent({\n * agentId: \"your-agent-id\",\n * accessKey: \"your-access-key\",\n * });\n *\n * const session = await agent.execute(\"Hello!\", {\n * onText: (text) => console.log(text),\n * onComplete: (fullText) => console.log(\"Done!\", fullText),\n * });\n * ```\n */\nexport class BuildShipAgent {\n /** @internal */ readonly _agentId: string;\n /** @internal */ readonly _accessKey?: string;\n /** @internal */ readonly _baseUrl: string;\n /** @internal */ readonly _clientTools = new Map<string, ClientTool>();\n\n constructor(config: AgentConfig) {\n if (!config.agentId) {\n throw new Error(\"BuildShipAgent: agentId is required\");\n }\n this._agentId = config.agentId;\n this._accessKey = config.accessKey;\n this._baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n }\n\n /**\n * The URL for the agent's execute endpoint.\n * @internal\n */\n get _url(): string {\n return `${this._baseUrl}/executeAgent/${this._agentId}`;\n }\n\n /**\n * Build the authorization / common headers.\n * @internal\n */\n _buildHeaders(sessionId?: SessionId): Record<string, string> {\n const headers: Record<string, string> = {};\n if (this._accessKey) {\n headers[\"Authorization\"] = `Bearer ${this._accessKey}`;\n }\n if (sessionId) {\n headers[\"X-BuildShip-Agent-Session-ID\"] = sessionId;\n }\n return headers;\n }\n\n // ─── Public API ────────────────────────────────────────────────────\n\n /**\n * Start a new conversation.\n *\n * Creates a fresh session and sends the first message.\n *\n * @param message - The message to send\n * @param callbacks - Event handlers for the stream\n * @param options - Optional execution settings (context, headers, body, onSessionId)\n * @returns The new session\n */\n async execute(\n message: string,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n const session = new AgentSession(this);\n await session.execute(message, callbacks, options);\n return session;\n }\n\n /**\n * Get an existing session by ID to continue a conversation.\n *\n * @param sessionId - The session ID from a previous conversation\n * @returns The session object\n */\n session(sessionId: SessionId | string): AgentSession {\n if (!sessionId) {\n throw new Error(\"BuildShipAgent.session(): sessionId is required\");\n }\n return new AgentSession(this, sessionId as SessionId);\n }\n\n /**\n * Register a client-side tool that the agent can call.\n */\n registerClientTool(tool: ClientTool): void {\n if (!tool.name) {\n throw new Error(\"registerClientTool: tool.name is required\");\n }\n this._clientTools.set(tool.name, tool);\n }\n\n /**\n * Remove a registered client tool.\n */\n unregisterClientTool(name: string): void {\n this._clientTools.delete(name);\n }\n}\n","// ─── Classes ─────────────────────────────────────────────────────────────────\nexport { BuildShipAgent } from \"./agent\";\nexport { AgentSession } from \"./session\";\n\n// ─── Stream executor ─────────────────────────────────────────────────────────\nexport { executeStream } from \"./stream\";\n\n// ─── Zod (re-exported for convenience) ───────────────────────────────────────\nexport { z, toJSONSchema } from \"zod\";\nexport type { ZodSchema } from \"zod\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\nexport type {\n AgentConfig,\n SessionId,\n ToolType,\n StreamCallbacks,\n StreamOptions,\n ExecuteRequestBody,\n ClientTool,\n PausedToolInfo,\n // Stream event types (for advanced consumers)\n StreamEvent,\n StreamEventMeta,\n TextDeltaEvent,\n ReasoningDeltaEvent,\n AgentHandoffEvent,\n ToolCallStartEvent,\n ToolCallEndEvent,\n RunErrorEvent,\n} from \"./types\";\n"],"mappings":"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","names":["toJSONSchema"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/stream.ts","../../src/core/session.ts","../../src/core/agent.ts","../../src/core/index.ts"],"sourcesContent":["import type { StreamEvent, StreamOptions, SessionId } from \"./types\";\n\n/** Safely parse a value as JSON if it's a string, otherwise return as-is. */\nfunction tryParseJSON(value: unknown): any {\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n }\n return value;\n}\n\n/**\n * Fatal error — will NOT be retried.\n */\nclass FatalStreamError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n ) {\n super(message);\n this.name = \"FatalStreamError\";\n }\n}\n\n/**\n * Opens an SSE connection to the BuildShip agent endpoint using native\n * `fetch` + `ReadableStream`, parses events, and dispatches to the\n * appropriate callbacks.\n *\n * Zero runtime dependencies — works in both browser and Node.js.\n *\n * @internal\n */\nexport async function executeStream(options: StreamOptions): Promise<void> {\n const {\n url,\n body,\n headers,\n callbacks,\n clientTools,\n signal,\n onSessionId,\n onPaused,\n onAutoResume,\n onResponse,\n } = options;\n\n let fullText = \"\";\n\n // Track pending auto-resume operations so we don't call onComplete prematurely\n const pendingAutoResumes: Promise<{ callId: string; result: unknown } | null>[] = [];\n\n // ── Make the request ────────────────────────────────────────────────\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n ...headers,\n },\n body: JSON.stringify(body),\n signal,\n });\n\n // ── Extract session ID and name from response headers ──────────────\n const sessionId = response.headers.get(\"X-BuildShip-Agent-Session-ID\");\n if (sessionId && onSessionId) {\n const sessionName = response.headers.get(\"X-BuildShip-Agent-Session-Name\") || undefined;\n onSessionId(sessionId as SessionId, sessionName);\n }\n\n // Expose the raw Response object\n onResponse?.(response);\n\n // ── Handle HTTP errors ─────────────────────────────────────────────\n if (!response.ok) {\n let errorBody = \"\";\n try {\n errorBody = await response.text();\n } catch {\n // ignore\n }\n const error = new FatalStreamError(\n `HTTP ${response.status}: ${errorBody || response.statusText}`,\n response.status,\n );\n callbacks.onError?.(error);\n throw error;\n }\n\n // ── Read the SSE stream ────────────────────────────────────────────\n if (!response.body) {\n callbacks.onComplete?.(fullText);\n return;\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop() || \"\";\n\n for (const part of parts) {\n const trimmedPart = part.trim();\n if (!trimmedPart) continue;\n\n // Extract the data field from SSE format\n let jsonStr = \"\";\n for (const line of trimmedPart.split(\"\\n\")) {\n if (line.startsWith(\"data: \")) {\n jsonStr += line.slice(6);\n } else if (line.startsWith(\"data:\")) {\n jsonStr += line.slice(5);\n }\n }\n\n jsonStr = jsonStr.trim();\n if (!jsonStr) continue;\n\n let raw: any;\n try {\n raw = JSON.parse(jsonStr);\n } catch {\n // Skip malformed events\n continue;\n }\n\n // Normalize backend event type names (llm_text_delta → text_delta, etc.)\n const streamEvent = normalizeEvent(raw) as StreamEvent;\n\n handleEvent(\n streamEvent,\n fullText,\n callbacks,\n clientTools,\n onPaused,\n onAutoResume,\n pendingAutoResumes,\n );\n\n // Accumulate text\n if (streamEvent.type === \"text_delta\") {\n fullText += streamEvent.data;\n }\n }\n }\n\n // Process any remaining data in buffer\n if (buffer.trim()) {\n let jsonStr = \"\";\n for (const line of buffer.trim().split(\"\\n\")) {\n if (line.startsWith(\"data: \")) {\n jsonStr += line.slice(6);\n } else if (line.startsWith(\"data:\")) {\n jsonStr += line.slice(5);\n }\n }\n\n jsonStr = jsonStr.trim();\n if (jsonStr) {\n try {\n const raw = JSON.parse(jsonStr);\n const streamEvent = normalizeEvent(raw) as StreamEvent;\n handleEvent(\n streamEvent,\n fullText,\n callbacks,\n clientTools,\n onPaused,\n onAutoResume,\n pendingAutoResumes,\n );\n if (streamEvent.type === \"text_delta\") {\n fullText += streamEvent.data;\n }\n } catch {\n // Skip malformed trailing data\n }\n }\n }\n } catch (err) {\n // AbortError — re-throw\n if (err instanceof Error && err.name === \"AbortError\") {\n throw err;\n }\n\n const error = err instanceof Error ? err : new Error(String(err));\n callbacks.onError?.(error);\n throw error;\n }\n\n // Wait for any pending auto-resume handlers before signaling completion\n if (pendingAutoResumes.length > 0) {\n const handlerResults = await Promise.allSettled(pendingAutoResumes);\n for (const settled of handlerResults) {\n if (settled.status === \"fulfilled\" && settled.value) {\n const { callId, result } = settled.value;\n await onAutoResume?.(callId, result);\n }\n }\n }\n\n callbacks.onComplete?.(fullText);\n}\n\n/**\n * Normalize backend event type names.\n * The backend sends `llm_text_delta` / `llm_reasoning_delta` but the SDK\n * exposes them as `text_delta` / `reasoning_delta`.\n * @internal\n */\nfunction normalizeEvent(raw: any): any {\n const typeMap: Record<string, string> = {\n llm_text_delta: \"text_delta\",\n llm_reasoning_delta: \"reasoning_delta\",\n };\n if (raw && typeof raw.type === \"string\" && typeMap[raw.type]) {\n raw.type = typeMap[raw.type];\n }\n return raw;\n}\n\n/**\n * Dispatch a parsed stream event to the appropriate callbacks.\n * @internal\n */\nfunction handleEvent(\n event: StreamEvent,\n _fullText: string,\n callbacks: StreamOptions[\"callbacks\"],\n clientTools: StreamOptions[\"clientTools\"],\n onPaused: StreamOptions[\"onPaused\"],\n onAutoResume: StreamOptions[\"onAutoResume\"],\n pendingAutoResumes: Promise<{ callId: string; result: unknown } | null>[],\n): void {\n // Notify raw event consumers\n callbacks.onEvent?.(event);\n\n switch (event.type) {\n case \"text_delta\": {\n callbacks.onText?.(event.data);\n break;\n }\n\n case \"reasoning_delta\": {\n callbacks.onReasoning?.(event.data.delta, event.data.index);\n break;\n }\n\n case \"agent_handoff\": {\n callbacks.onAgentHandoff?.(event.data.agentName);\n break;\n }\n\n case \"tool_call_start\": {\n const { callId, toolName, toolType, inputs: rawInputs, paused } = event.data;\n // Backend sends toolCall.arguments as a JSON string — parse it\n const inputs = tryParseJSON(rawInputs);\n\n // Notify callback\n callbacks.onToolStart?.(toolName, toolType);\n\n // Handle client tools\n if (toolType === \"client\") {\n const tool = clientTools.get(toolName);\n if (tool) {\n if (paused && tool.handler) {\n // Blocking tool with handler → auto-execute and resume\n const handlerPromise = (async (): Promise<{\n callId: string;\n result: unknown;\n } | null> => {\n try {\n const result = await tool.handler!(inputs);\n\n // Synthesize a tool_call_end event for local observers (like debug panels)\n // since the backend only emits for server-side executed tools\n callbacks.onEvent?.({\n type: \"tool_call_end\",\n data: {\n callId,\n toolName,\n toolType: \"client\",\n result,\n },\n meta: event.meta,\n });\n\n return { callId, result };\n } catch (error) {\n // If handler fails, still call onPaused so user can decide\n callbacks.onPaused?.(toolName, inputs);\n onPaused?.({ callId, toolName, args: inputs });\n return null;\n }\n })();\n pendingAutoResumes.push(handlerPromise);\n } else if (paused) {\n // Blocking tool without handler → pause for user\n callbacks.onPaused?.(toolName, inputs);\n onPaused?.({ callId, toolName, args: inputs });\n } else if (tool.handler) {\n // Fire-and-forget tool with handler\n try {\n tool.handler(inputs);\n } catch {\n // Swallow errors on fire-and-forget\n }\n }\n } else if (paused) {\n // No registered tool but paused — notify user\n callbacks.onPaused?.(toolName, inputs);\n onPaused?.({ callId, toolName, args: inputs });\n }\n }\n break;\n }\n\n case \"tool_call_end\": {\n const { toolName, result, error } = event.data;\n callbacks.onToolEnd?.(toolName, result, error);\n break;\n }\n\n case \"run_error\": {\n const { message, code } = event.data;\n const error = new Error(message);\n if (code != null) (error as any).code = code;\n callbacks.onError?.(error);\n break;\n }\n }\n}\n","import type {\n AgentInput,\n SessionId,\n StreamCallbacks,\n PausedToolInfo,\n ExecuteRequestBody,\n ExecuteOptions,\n} from \"./types\";\nimport type { BuildShipAgent } from \"./agent\";\nimport { executeStream } from \"./stream\";\nimport { toJSONSchema, type ZodSchema } from \"zod\";\n\n/**\n * Represents a conversation session with a BuildShip agent.\n *\n * Sessions maintain history across multiple turns and support\n * pause/resume for blocking client tools.\n */\nexport class AgentSession {\n /** @internal */ private _agent: BuildShipAgent;\n /** @internal */ private _sessionId: SessionId | undefined;\n /** @internal */ private _paused = false;\n /** @internal */ private _pausedToolInfo: PausedToolInfo | null = null;\n /** @internal */ private _abortController: AbortController | null = null;\n\n /** @internal */\n constructor(agent: BuildShipAgent, sessionId?: SessionId) {\n this._agent = agent;\n this._sessionId = sessionId;\n }\n\n // ─── Public API ────────────────────────────────────────────────────\n\n /**\n * Send a message in this session.\n *\n * @param message - The message to send\n * @param callbacks - Event handlers for the stream\n * @param callbacks - Event handlers for the stream\n * @param options - Optional settings like context, headers, or body\n * @returns This session (for chaining)\n */\n async execute(\n message: AgentInput,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n this._paused = false;\n this._pausedToolInfo = null;\n\n const body: ExecuteRequestBody = {\n ...(options?.body || {}),\n input: message,\n stream: true,\n };\n\n // Attach context as top-level properties if provided\n if (options?.context) {\n Object.assign(body, { context: options.context });\n }\n\n // Include client tool definitions\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n body.clientTools = clientToolDefs;\n }\n\n await this._run(body, callbacks, options);\n return this;\n }\n\n /**\n * Resume a paused session with a tool result.\n *\n * @param result - The result to send back to the agent\n * @param callbacks - Event handlers for the resumed stream\n * @param options - Optional settings like headers or body\n * @returns This session (for chaining)\n */\n async resume(\n result: any,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n if (!this._paused || !this._pausedToolInfo) {\n throw new Error(\"AgentSession.resume(): session is not paused. Check isPaused() first.\");\n }\n\n const body: ExecuteRequestBody = {\n ...(options?.body || {}),\n stream: true,\n toolCallResult: {\n callId: this._pausedToolInfo.callId,\n result,\n },\n };\n\n // Attach context if provided\n if (options?.context) {\n Object.assign(body, { context: options.context });\n }\n\n // Include client tool definitions for resume requests too\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n body.clientTools = clientToolDefs;\n }\n\n this._paused = false;\n this._pausedToolInfo = null;\n\n await this._run(body, callbacks, options);\n return this;\n }\n\n /**\n * Resume a session with an explicit tool call ID and result.\n *\n * Unlike `resume()`, this does NOT require the session to be in a paused state,\n * making it suitable for external resume flows (e.g. React widget submissions)\n * where the session object may have been re-created.\n *\n * @param callId - The tool call ID to resume\n * @param result - The result to send back to the agent\n * @param callbacks - Event handlers for the resumed stream\n * @param options - Optional settings like headers or body\n * @returns This session (for chaining)\n */\n async resumeWithCallId(\n callId: string,\n result: any,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n const body: ExecuteRequestBody = {\n ...(options?.body || {}),\n stream: true,\n toolCallResult: { callId, result },\n };\n\n // Attach context if provided\n if (options?.context) {\n Object.assign(body, { context: options.context });\n }\n\n // Include client tool definitions for resume requests too\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n body.clientTools = clientToolDefs;\n }\n\n // Clear any stale pause state\n this._paused = false;\n this._pausedToolInfo = null;\n\n await this._run(body, callbacks, options);\n return this;\n }\n\n /**\n * Check if this session is waiting for a tool result.\n */\n isPaused(): boolean {\n return this._paused;\n }\n\n /**\n * Get information about the paused tool call.\n * Returns `null` if the session is not paused.\n */\n getPausedTool(): PausedToolInfo | null {\n return this._pausedToolInfo;\n }\n\n /**\n * Get the session ID.\n * May be `undefined` if the session hasn't executed yet.\n */\n getSessionId(): SessionId {\n if (!this._sessionId) {\n throw new Error(\n \"AgentSession.getSessionId(): session ID not yet available. Call execute() first.\",\n );\n }\n return this._sessionId;\n }\n\n /**\n * Cancel the current streaming operation.\n */\n abort(): void {\n this._abortController?.abort();\n this._abortController = null;\n }\n\n // ─── Private helpers ───────────────────────────────────────────────\n\n /** @internal */\n private async _run(\n body: ExecuteRequestBody,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<void> {\n // Create a fresh abort controller for this run\n this._abortController = new AbortController();\n\n const baseHeaders = this._agent._buildHeaders(this._sessionId);\n const mergedHeaders = { ...baseHeaders, ...(options?.headers || {}) };\n\n await executeStream({\n url: this._agent._url,\n body,\n headers: mergedHeaders,\n callbacks,\n clientTools: this._agent._clientTools,\n signal: this._abortController.signal,\n\n onSessionId: (id, name) => {\n this._sessionId = id;\n options?.onSessionId?.(id, name);\n },\n\n onPaused: (info) => {\n this._paused = true;\n this._pausedToolInfo = info;\n },\n\n onAutoResume: async (callId, result) => {\n // Auto-resume: send the tool result back immediately\n const resumeBody: ExecuteRequestBody = {\n ...(options?.body || {}),\n stream: true,\n toolCallResult: { callId, result },\n };\n\n // Carry context forward from the original execute options\n if (options?.context) {\n Object.assign(resumeBody, { context: options.context });\n }\n\n const clientToolDefs = this._getClientToolDefs();\n if (clientToolDefs.length > 0) {\n resumeBody.clientTools = clientToolDefs;\n }\n\n await this._run(resumeBody, callbacks, options);\n },\n });\n }\n\n /** @internal */\n private _getClientToolDefs() {\n const defs: ExecuteRequestBody[\"clientTools\"] = [];\n for (const tool of this._agent._clientTools.values()) {\n defs.push({\n name: tool.name,\n description: tool.description,\n parameters: resolveParameters(tool.parameters),\n await: tool.await,\n });\n }\n return defs;\n }\n}\n\n/**\n * Convert tool parameters to a JSON Schema object.\n * - If it's a Zod schema, uses Zod's built-in `toJSONSchema` to convert.\n * - Always ensures `additionalProperties: false` is set (required by the backend).\n * - Always ensures `required` includes every key in `properties` (Gemini requirement).\n * @internal\n */\nfunction resolveParameters(params: any): Record<string, any> {\n let schema: Record<string, any>;\n\n // Detect Zod schema: ZodType instances have a `_def` property\n if (params && typeof params === \"object\" && \"_def\" in params) {\n schema = toJSONSchema(params as ZodSchema) as Record<string, any>;\n // Remove $schema key if present\n delete schema.$schema;\n } else {\n schema = { ...params };\n }\n\n if (schema.type === \"object\") {\n // Backend requires additionalProperties: false\n schema.additionalProperties = false;\n\n // Gemini requires `required` to include every key in `properties`\n if (schema.properties) {\n schema.required = Object.keys(schema.properties);\n }\n }\n\n return schema;\n}\n","import type {\n AgentConfig,\n AgentInput,\n ClientTool,\n ExecuteOptions,\n SessionId,\n StreamCallbacks,\n} from \"./types\";\nimport { AgentSession } from \"./session\";\n\nconst DEFAULT_BASE_URL = \"https://api.buildship.run\";\n\n/**\n * Main entry point for interacting with a BuildShip agent.\n *\n * @example\n * ```ts\n * import { BuildShipAgent } from \"buildship-agent-sdk/core\";\n *\n * const agent = new BuildShipAgent({\n * agentId: \"your-agent-id\",\n * accessKey: \"your-access-key\",\n * });\n *\n * const session = await agent.execute(\"Hello!\", {\n * onText: (text) => console.log(text),\n * onComplete: (fullText) => console.log(\"Done!\", fullText),\n * });\n * ```\n */\nexport class BuildShipAgent {\n /** @internal */ readonly _agentId: string;\n /** @internal */ readonly _accessKey?: string;\n /** @internal */ readonly _baseUrl: string;\n /** @internal */ readonly _clientTools = new Map<string, ClientTool>();\n\n constructor(config: AgentConfig) {\n if (!config.agentId) {\n throw new Error(\"BuildShipAgent: agentId is required\");\n }\n this._agentId = config.agentId;\n this._accessKey = config.accessKey;\n this._baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n }\n\n /**\n * The URL for the agent's execute endpoint.\n * @internal\n */\n get _url(): string {\n return `${this._baseUrl}/executeAgent/${this._agentId}`;\n }\n\n /**\n * Build the authorization / common headers.\n * @internal\n */\n _buildHeaders(sessionId?: SessionId): Record<string, string> {\n const headers: Record<string, string> = {};\n if (this._accessKey) {\n headers[\"Authorization\"] = `Bearer ${this._accessKey}`;\n }\n if (sessionId) {\n headers[\"X-BuildShip-Agent-Session-ID\"] = sessionId;\n }\n return headers;\n }\n\n // ─── Public API ────────────────────────────────────────────────────\n\n /**\n * Start a new conversation.\n *\n * Creates a fresh session and sends the first message.\n *\n * @param message - The message to send\n * @param callbacks - Event handlers for the stream\n * @param options - Optional execution settings (context, headers, body, onSessionId)\n * @returns The new session\n */\n async execute(\n message: AgentInput,\n callbacks: StreamCallbacks,\n options?: ExecuteOptions,\n ): Promise<AgentSession> {\n const session = new AgentSession(this);\n await session.execute(message, callbacks, options);\n return session;\n }\n\n /**\n * Get an existing session by ID to continue a conversation.\n *\n * @param sessionId - The session ID from a previous conversation\n * @returns The session object\n */\n session(sessionId: SessionId | string): AgentSession {\n if (!sessionId) {\n throw new Error(\"BuildShipAgent.session(): sessionId is required\");\n }\n return new AgentSession(this, sessionId as SessionId);\n }\n\n /**\n * Register a client-side tool that the agent can call.\n */\n registerClientTool(tool: ClientTool): void {\n if (!tool.name) {\n throw new Error(\"registerClientTool: tool.name is required\");\n }\n this._clientTools.set(tool.name, tool);\n }\n\n /**\n * Remove a registered client tool.\n */\n unregisterClientTool(name: string): void {\n this._clientTools.delete(name);\n }\n}\n","// ─── Classes ─────────────────────────────────────────────────────────────────\nexport { BuildShipAgent } from \"./agent\";\nexport { AgentSession } from \"./session\";\n\n// ─── Stream executor ─────────────────────────────────────────────────────────\nexport { executeStream } from \"./stream\";\n\n// ─── Zod (re-exported for convenience) ───────────────────────────────────────\nexport { z, toJSONSchema } from \"zod\";\nexport type { ZodSchema } from \"zod\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\nexport type {\n AgentConfig,\n AgentInput,\n SessionId,\n ToolType,\n StreamCallbacks,\n StreamOptions,\n ExecuteRequestBody,\n ClientTool,\n PausedToolInfo,\n // Multimodal input types\n ContentPart,\n TextPart,\n ImagePart,\n FilePart,\n // Stream event types (for advanced consumers)\n StreamEvent,\n StreamEventMeta,\n TextDeltaEvent,\n ReasoningDeltaEvent,\n AgentHandoffEvent,\n ToolCallStartEvent,\n ToolCallEndEvent,\n RunErrorEvent,\n} from \"./types\";\n"],"mappings":"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","names":["toJSONSchema"]}
|
package/dist/react/index.cjs
CHANGED
|
@@ -372,23 +372,17 @@ function buildStreamCallbacks(deps, debugKey) {
|
|
|
372
372
|
return {
|
|
373
373
|
onComplete: () => {
|
|
374
374
|
console.log("Agent closed");
|
|
375
|
-
setMessages((current) => {
|
|
376
|
-
if (syncSessionRef.current) {
|
|
377
|
-
syncSessionRef.current(current);
|
|
378
|
-
}
|
|
379
|
-
return current;
|
|
380
|
-
});
|
|
381
375
|
setInProgress(false);
|
|
376
|
+
if (syncSessionRef.current) {
|
|
377
|
+
syncSessionRef.current(messagesRef.current);
|
|
378
|
+
}
|
|
382
379
|
},
|
|
383
380
|
onError: (error) => {
|
|
384
381
|
console.log("Agent error", error);
|
|
385
|
-
setMessages((current) => {
|
|
386
|
-
if (syncSessionRef.current) {
|
|
387
|
-
syncSessionRef.current(current);
|
|
388
|
-
}
|
|
389
|
-
return current;
|
|
390
|
-
});
|
|
391
382
|
setInProgress(false);
|
|
383
|
+
if (syncSessionRef.current) {
|
|
384
|
+
syncSessionRef.current(messagesRef.current);
|
|
385
|
+
}
|
|
392
386
|
},
|
|
393
387
|
onEvent: (event) => {
|
|
394
388
|
if (event.type === "text_delta") {
|
|
@@ -515,25 +509,7 @@ function handleTextDelta(event, setMessages, syncSessionRef, modifier, fullTextM
|
|
|
515
509
|
}
|
|
516
510
|
function handleClientToolCall(event, setMessages, syncSessionRef, toolContext, agentId) {
|
|
517
511
|
const tool = toolContext?.getTool(agentId, event.data.toolName);
|
|
518
|
-
|
|
519
|
-
"[DEBUG] handleClientToolCall:",
|
|
520
|
-
event.data.toolName,
|
|
521
|
-
"paused:",
|
|
522
|
-
event.data.paused,
|
|
523
|
-
"toolFound:",
|
|
524
|
-
!!tool,
|
|
525
|
-
"hasRender:",
|
|
526
|
-
!!tool?.render
|
|
527
|
-
);
|
|
528
|
-
if (!tool?.render && !event.data.paused) {
|
|
529
|
-
console.log("[DEBUG] handleClientToolCall: SKIPPING part creation \u2014 not paused and no render");
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
console.log(
|
|
533
|
-
"[DEBUG] handleClientToolCall: CREATING widget part for",
|
|
534
|
-
event.data.toolName,
|
|
535
|
-
event.data.callId
|
|
536
|
-
);
|
|
512
|
+
if (!tool?.render) return;
|
|
537
513
|
setMessages((prev) => {
|
|
538
514
|
const lastMessage = prev[prev.length - 1];
|
|
539
515
|
const newPart = {
|
|
@@ -701,11 +677,29 @@ function useAgent(agent, options) {
|
|
|
701
677
|
);
|
|
702
678
|
const handleSend = (0, import_react3.useCallback)(
|
|
703
679
|
async (input, options2) => {
|
|
680
|
+
let displayText;
|
|
681
|
+
let attachments;
|
|
682
|
+
if (typeof input === "string") {
|
|
683
|
+
displayText = input;
|
|
684
|
+
} else {
|
|
685
|
+
const textParts = [];
|
|
686
|
+
const mediaParts = [];
|
|
687
|
+
for (const part of input) {
|
|
688
|
+
if (part.type === "text") {
|
|
689
|
+
textParts.push(part.text);
|
|
690
|
+
} else {
|
|
691
|
+
mediaParts.push(part);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
displayText = textParts.join("\n");
|
|
695
|
+
if (mediaParts.length > 0) attachments = mediaParts;
|
|
696
|
+
}
|
|
704
697
|
const userMessage = {
|
|
705
698
|
role: "user",
|
|
706
|
-
content:
|
|
699
|
+
content: displayText,
|
|
707
700
|
executionId: Date.now().toString(),
|
|
708
|
-
...options2?.context ? { context: options2.context } : {}
|
|
701
|
+
...options2?.context ? { context: options2.context } : {},
|
|
702
|
+
...attachments ? { attachments } : {}
|
|
709
703
|
};
|
|
710
704
|
if (!options2?.skipUserMessage) {
|
|
711
705
|
setMessages((prev) => {
|
|
@@ -715,14 +709,15 @@ function useAgent(agent, options) {
|
|
|
715
709
|
}
|
|
716
710
|
return updatedMessages;
|
|
717
711
|
});
|
|
718
|
-
} else if (options2?.context) {
|
|
712
|
+
} else if (options2?.context || attachments) {
|
|
719
713
|
setMessages((prev) => {
|
|
720
714
|
const lastUserIdx = prev.findLastIndex((m) => m.role === "user");
|
|
721
715
|
if (lastUserIdx === -1) return prev;
|
|
722
716
|
const updatedMessages = [...prev];
|
|
723
717
|
updatedMessages[lastUserIdx] = {
|
|
724
718
|
...updatedMessages[lastUserIdx],
|
|
725
|
-
context: options2.context
|
|
719
|
+
...options2?.context ? { context: options2.context } : {},
|
|
720
|
+
...attachments ? { attachments } : {}
|
|
726
721
|
};
|
|
727
722
|
if (sessionUtils.syncSessionRef.current) {
|
|
728
723
|
sessionUtils.syncSessionRef.current(updatedMessages);
|
|
@@ -797,10 +792,28 @@ function useAgent(agent, options) {
|
|
|
797
792
|
);
|
|
798
793
|
const addOptimisticMessage = (0, import_react3.useCallback)(
|
|
799
794
|
(input) => {
|
|
795
|
+
let displayText;
|
|
796
|
+
let attachments;
|
|
797
|
+
if (typeof input === "string") {
|
|
798
|
+
displayText = input;
|
|
799
|
+
} else {
|
|
800
|
+
const textParts = [];
|
|
801
|
+
const mediaParts = [];
|
|
802
|
+
for (const part of input) {
|
|
803
|
+
if (part.type === "text") {
|
|
804
|
+
textParts.push(part.text);
|
|
805
|
+
} else {
|
|
806
|
+
mediaParts.push(part);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
displayText = textParts.join("\n");
|
|
810
|
+
if (mediaParts.length > 0) attachments = mediaParts;
|
|
811
|
+
}
|
|
800
812
|
const userMessage = {
|
|
801
813
|
role: "user",
|
|
802
|
-
content:
|
|
803
|
-
executionId: Date.now().toString()
|
|
814
|
+
content: displayText,
|
|
815
|
+
executionId: Date.now().toString(),
|
|
816
|
+
...attachments ? { attachments } : {}
|
|
804
817
|
};
|
|
805
818
|
setMessages((prev) => {
|
|
806
819
|
const updatedMessages = [...prev, userMessage];
|
|
@@ -821,34 +834,19 @@ function useAgent(agent, options) {
|
|
|
821
834
|
sessionUtils.syncSessionRef.current(messagesRef.current);
|
|
822
835
|
}
|
|
823
836
|
}, [sessionUtils.syncSessionRef]);
|
|
824
|
-
return
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
}),
|
|
838
|
-
[
|
|
839
|
-
inProgress,
|
|
840
|
-
messages,
|
|
841
|
-
handleSend,
|
|
842
|
-
resumeTool,
|
|
843
|
-
addOptimisticMessage,
|
|
844
|
-
abort,
|
|
845
|
-
currentSessionId,
|
|
846
|
-
sessionUtils.switchSession,
|
|
847
|
-
sessionUtils.deleteSession,
|
|
848
|
-
sessionUtils.sessionsList,
|
|
849
|
-
debugData
|
|
850
|
-
]
|
|
851
|
-
);
|
|
837
|
+
return {
|
|
838
|
+
inProgress,
|
|
839
|
+
messages,
|
|
840
|
+
handleSend,
|
|
841
|
+
resumeTool,
|
|
842
|
+
addOptimisticMessage,
|
|
843
|
+
abort,
|
|
844
|
+
sessionId: currentSessionId,
|
|
845
|
+
switchSession: sessionUtils.switchSession,
|
|
846
|
+
deleteSession: sessionUtils.deleteSession,
|
|
847
|
+
sessions: sessionUtils.sessionsList,
|
|
848
|
+
debugData
|
|
849
|
+
};
|
|
852
850
|
}
|
|
853
851
|
|
|
854
852
|
// src/core/stream.ts
|
|
@@ -1667,19 +1665,6 @@ function ToolRenderer({ agentId, part }) {
|
|
|
1667
1665
|
throw new Error("ToolRenderer must be used within <AgentContextProvider>");
|
|
1668
1666
|
}
|
|
1669
1667
|
const tool = context.getTool(agentId, part.toolName);
|
|
1670
|
-
console.log(
|
|
1671
|
-
"[DEBUG] ToolRenderer:",
|
|
1672
|
-
part.toolName,
|
|
1673
|
-
part.callId,
|
|
1674
|
-
"toolFound:",
|
|
1675
|
-
!!tool,
|
|
1676
|
-
"hasRender:",
|
|
1677
|
-
!!tool?.render,
|
|
1678
|
-
"paused:",
|
|
1679
|
-
part.paused,
|
|
1680
|
-
"status:",
|
|
1681
|
-
localStatus
|
|
1682
|
-
);
|
|
1683
1668
|
const handleSubmit = (0, import_react6.useCallback)(
|
|
1684
1669
|
(result) => {
|
|
1685
1670
|
if (localStatus === "submitted") return;
|