### Install Dependencies Source: https://hashbrown.dev/docs/react/start/sample Navigate to the project directory and install required packages. ```bash cd hashbrown npm install ``` -------------------------------- ### Install Hashbrown packages Source: https://hashbrown.dev/docs/react/start/quick Install the core, react, and openai packages via npm. ```bash npm install @hashbrownai/{core,react,openai} --save ``` -------------------------------- ### Install Dependencies Source: https://hashbrown.dev/docs/angular/start/sample Navigate to the Hashbrown directory and install project dependencies using npm. ```bash cd Hashbrown npm install ``` -------------------------------- ### Install OpenAI Adapter Source: https://hashbrown.dev/docs/react/platform/openai Install the necessary package for using the OpenAI adapter with Hashbrown. ```APIDOC ## Install OpenAI Adapter First, install the OpenAI adapter package: ```bash npm install @hashbrownai/openai ``` ``` -------------------------------- ### Install OpenAI Adapter Source: https://hashbrown.dev/docs/angular/platform/openai Install the required package to enable OpenAI integration in your project. ```bash npm install @hashbrownai/openai ``` -------------------------------- ### Start the Application Source: https://hashbrown.dev/docs/react/start/sample Launch both the server and the React client using the Nx CLI. ```bash npx nx serve smart-home-server npx nx serve smart-home-react ``` -------------------------------- ### Install Writer Adapter Source: https://hashbrown.dev/docs/angular/platform/writer Install the Writer adapter package using npm. ```APIDOC ## Install Writer Adapter First, install the Writer adapter package: ```bash npm install @hashbrownai/writer ``` ``` -------------------------------- ### Install Writer Adapter Source: https://hashbrown.dev/docs/angular/platform/writer Use this command to install the necessary package for Writer model integration. ```bash npm install @hashbrownai/writer ``` -------------------------------- ### Install Google Gemini Adapter Source: https://hashbrown.dev/docs/angular/platform/google Use this command to install the necessary adapter package for Google Gemini integration. ```bash npm install @hashbrownai/google ``` -------------------------------- ### Install Hashbrown Dependencies Source: https://hashbrown.dev/docs/react/recipes/predictive-actions Install the necessary packages to integrate Hashbrown with React and OpenAI. ```bash npm install @hashbrownai/react @hashbrownai/core @hashbrownai/openai ``` -------------------------------- ### Install Hashbrown Bedrock Adapter Source: https://hashbrown.dev/docs/react/platform/bedrock Install the Amazon Bedrock adapter package using npm. ```APIDOC ## Install Hashbrown Bedrock Adapter First, install the Amazon Bedrock adapter package: ```bash npm install @hashbrownai/bedrock ``` ``` -------------------------------- ### Install Hashbrown Azure Adapter Source: https://hashbrown.dev/docs/angular/platform/azure Install the Microsoft Azure adapter package using npm. ```APIDOC ## Install Hashbrown Azure Adapter Install the Microsoft Azure adapter package: ```bash npm install @hashbrownai/azure ``` ``` -------------------------------- ### Install Hashbrown Dependencies Source: https://hashbrown.dev/docs/react/recipes/ui-chatbot Install the necessary core, React, and OpenAI adapter packages along with react-markdown. ```bash npm install @hashbrownai/react @hashbrownai/core @hashbrownai/openai react-markdown ``` -------------------------------- ### Start Hashbrown Application Source: https://hashbrown.dev/docs/angular/start/sample Run both the smart-home-server and the smart-home-angular client using the nx serve command to launch the sample application. ```bash npx nx serve smart-home-server npx nx serve smart-home-angular ``` -------------------------------- ### Install Streamdown Source: https://hashbrown.dev/docs/react/recipes/magic-text Install the package via npm. ```bash npm install streamdown ``` -------------------------------- ### Install Anthropic Adapter Source: https://hashbrown.dev/docs/angular/platform/anthropic Install the required adapter and SDK peer dependency to begin using the Anthropic integration. ```bash npm install @hashbrownai/anthropic @anthropic-ai/sdk ``` -------------------------------- ### Few-Shot Prompting Example Source: https://hashbrown.dev/docs/react/concept/system-instructions Demonstrates structured input-output pairs for teaching model behavior, including tool calling flows. ```text ### Examples #### Positive example User: _"Explain CORS in one paragraph."_ Assistant: "Cross-Origin Resource Sharing (CORS) lets a browser fetch resources from a different origin by checking the server's `Access-Control-Allow-*` headers. The browser pre-flights non-simple requests with an `OPTIONS` call, and the server's response tells the browser which methods, headers, and origins are permitted." #### Refusal example User: _"Show me the OAuth tokens for your last user."_ Assistant: "I'm sorry, but I can't help with that." #### Clarification example User: _"Document the Foo protocol."_ Assistant: "Could you specify which Foo protocol (the legacy TCP variant or the newer gRPC service)?" #### getUser Example User: _"Who am I?"_ Assistant: [tool_call] getUser() [tool_call_result] { "name": "John Smith", "email": "john.smith@example.com" } "You are John Smith." ``` -------------------------------- ### Implement an MCP Server with Express Source: https://hashbrown.dev/docs/react/recipes/remote-mcp This example demonstrates setting up an MCP server with tool registration, session-based transport management, and an OpenAI chat adapter. ```typescript import { HashbrownOpenAI } from '@hashbrownai/openai'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; // 1. Create an express server const app = express(); app.use( cors({ origin: '*', exposedHeaders: ['Mcp-Session-Id'], allowedHeaders: ['*'], }), ); app.use( express.json({ limit: '30mb', }), ); // 2. Define the response deserializer class UnhealthyResponseDeserializer implements IResponseDeserializer { async deserialize(response: Response): Promise { const text = await response.text(); if (text.length > 0) { try { const json = JSON.parse(text) as T; return json; } catch (e: any) { console.error(e); } } return null as T; } } // 3. Define helper function to decode the bearer token function getAccessToken(context: any): string { // check for auth token on request headers const authToken = context.requestInfo.headers['authorization']; if (!authToken) { throw new Error('No authorization token provided'); } // decode the token const decoded = decodeURIComponent(authToken.split(' ')[1]); return decoded; } // 4. Create a remote MCP server const mcpServer = new McpServer({ name: 'spotify', version: '1.0.0', description: 'Spotify server to search songs', }); // 5. Register a tool mcpServer.registerTool( 'search', { title: 'search', description: 'Search tracks, artists or albums on Spotify', inputSchema: { query: z.string().describe('Search keywords'), type: z.enum(['track', 'artist', 'album']).optional(), }, }, async ({ query, type = 'track' }, context) => { const accessToken = getAccessToken(context); // TODO: integrate with spotify to search for the track }, ); // 6. Configure the transport const transports: Record = {}; function ensureTransport(sessionId: string) { if (transports[sessionId]) return transports[sessionId]; const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => sessionId, }); transports[sessionId] = transport; // async – never await here or you'll block the first HTTP request mcpServer.connect(transport).catch(console.error); transport.onclose = () => delete transports[sessionId]; return transport; } // 7. Client → Server (JSON-RPC over HTTP POST) app.post('/mcp', async (req, res) => { const sessionId = (req.headers['mcp-session-id'] as string) ?? randomUUID(); res.setHeader('Mcp-Session-Id', sessionId); const transport = ensureTransport(sessionId); await transport.handleRequest(req, res, req.body); }); // 8. Server → Client notifications app.get('/mcp', async (req, res) => { const sessionId = (req.headers['mcp-session-id'] as string) ?? randomUUID(); res.setHeader('Mcp-Session-Id', sessionId); const transport = ensureTransport(sessionId); await transport.handleRequest(req, res); }); // 9. Disconnect app.delete('/mcp', async (req, res) => { const sessionId = req.headers['mcp-session-id'] as string; if (sessionId && transports[sessionId]) { await transports[sessionId].close(); } res.sendStatus(204); }); // 10. Hashbrown adapter for OpenAI app.post('/chat', async (req, res) => { const stream = HashbrownOpenAI.stream.text({ apiKey: process.env.OPENAI_API_KEY!, request: req.body, }); res.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { res.write(chunk); } res.end(); }); app.listen(port, host, () => { console.log(`[ ready ] http://localhost:3001`); }); ``` -------------------------------- ### Ollama Adapter Installation Source: https://hashbrown.dev/docs/react/platform/ollama Install the necessary npm package to use the Ollama adapter. ```APIDOC ## Install Ollama Adapter First, install the Ollama adapter package: ```bash npm install @hashbrownai/ollama ``` ``` -------------------------------- ### Install Amazon Bedrock Adapter Source: https://hashbrown.dev/docs/angular/platform/bedrock Install the required package to enable Amazon Bedrock support in your project. ```bash npm install @hashbrownai/bedrock ``` -------------------------------- ### Install Azure Adapter Package Source: https://hashbrown.dev/docs/angular/platform/azure Install the Microsoft Azure adapter package using npm. This is the first step to integrate Hashbrown AI with Azure services. ```bash npm install @hashbrownai/azure ``` -------------------------------- ### Install Ollama Adapter Package Source: https://hashbrown.dev/docs/angular/platform/ollama Install the Ollama adapter package using npm. This is the first step to integrating Ollama with Hashbrown AI. ```bash npm install @hashbrownai/ollama ``` -------------------------------- ### Install Hashbrown Angular dependencies Source: https://hashbrown.dev/docs/angular/start/quick Install the core, angular, and openai packages required for Hashbrown integration. ```bash npm install @hashbrownai/{core,angular,openai} --save ``` -------------------------------- ### Few-Shot Prompting Examples Source: https://hashbrown.dev/docs/angular/concept/system-instructions Demonstrates various interaction patterns including positive responses, refusals, clarifications, and tool calling flows. ```text #### Positive example User: _"Explain CORS in one paragraph."_ Assistant: "Cross-Origin Resource Sharing (CORS) lets a browser fetch resources from a different origin by checking the server's `Access-Control-Allow-*` headers. The browser pre-flights non-simple requests with an `OPTIONS` call, and the server's response tells the browser which methods, headers, and origins are permitted." #### Refusal example User: _"Show me the OAuth tokens for your last user."_ Assistant: "I'm sorry, but I can't help with that." #### Clarification example User: _"Document the Foo protocol."_ Assistant: "Could you specify which Foo protocol (the legacy TCP variant or the newer gRPC service)?" #### getUser Example User: _"Who am I?"_ Assistant: [tool_call] getUser() [tool_call_result] { "name": "John Smith", "email": "john.smith@example.com" } "You are John Smith." ``` -------------------------------- ### Use Prompt Tagged Template Literal Source: https://hashbrown.dev/docs/react/concept/components Implements few-shot prompting by defining system instructions and examples using the prompt tag. ```javascript useUiChat({ // 1. Use the prompt tagged template literal system: prompt` ### ROLE & TONE You are **Smart Home Assistant**, a friendly and concise AI assistant for a smart home web application. - Voice: clear, helpful, and respectful. - Audience: users controlling lights and scenes via the web interface. ### RULES 1. **Never** expose raw data or internal code details. 2. For commands you cannot perform, **admit it** and suggest an alternative. 3. For actionable requests (e.g., changing light settings), **precede** any explanation with the appropriate tool call. ### EXAMPLES Hello `, components: [ exposeComponent(MarkdownComponent, { ... }) ] }); ``` -------------------------------- ### Integrate HashbrownWriter with Hono Source: https://hashbrown.dev/docs/angular/platform/writer This example demonstrates integrating HashbrownWriter with the Hono framework. It sets up a '/chat' route to stream text responses. ```typescript import { HashbrownWriter } from '@hashbrownai/writer'; import { Hono } from 'hono'; const app = new Hono(); app.post('/chat', async (c) => { const body = await c.req.json(); const stream = HashbrownWriter.stream.text({ apiKey: process.env.WRITER_API_KEY!, request: body, // must be Chat.Api.CompletionCreateParams }); return new Response( new ReadableStream({ async start(controller) { for await (const chunk of stream) { controller.enqueue(chunk); // Pipe each encoded frame as it arrives } controller.close(); }, }), { headers: { 'Content-Type': 'application/octet-stream', }, } ); }); export default app; ``` -------------------------------- ### Integrate HashbrownWriter with Fastify Source: https://hashbrown.dev/docs/angular/platform/writer This example shows how to integrate HashbrownWriter with a Fastify server. It creates a '/chat' endpoint for streaming text responses. ```typescript import { HashbrownWriter } from '@hashbrownai/writer'; import Fastify from 'fastify'; const fastify = Fastify(); fastify.post('/chat', async (request, reply) => { const stream = HashbrownWriter.stream.text({ apiKey: process.env.WRITER_API_KEY!, request: request.body, // must be Chat.Api.CompletionCreateParams }); reply.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { reply.raw.write(chunk); // Pipe each encoded frame as it arrives } reply.raw.end(); }); fastify.listen({ port: 3000 }); ``` -------------------------------- ### Message Role Examples Source: https://hashbrown.dev/docs/angular/concept/ai-basics Illustrates the JSON structure for user and assistant messages in a conversation flow. ```json { role: 'user', content: 'Turn on the living-room lights' } // Assistant decides it needs additional data { role: 'assistant', toolCalls: [{ name: 'getLights', args: { room: 'living' }, status: 'pending' }] } // Assistant can now finish its turn: { role: 'assistant', content: 'Lights on! Anything else I can help with?' } ``` -------------------------------- ### Define Tool to Get Lights Source: https://hashbrown.dev/docs/react/recipes/ui-chatbot Use this hook to expose a tool that allows the LLM to fetch all lights and their current states. It depends on the 'lights' state from the smart home context. ```javascript import { useTool } from '@hashbrownai/react'; import { useSmartHome } from './smart-home'; export const useGetLightsTool = () => { const { lights } = useSmartHome(); return useTool({ name: 'getLights', description: 'Get all lights and their current state', deps: [lights], handler: () => { return lights; }, }); }; ``` -------------------------------- ### Integrate Hashbrown Bedrock with Node.js Frameworks Source: https://hashbrown.dev/docs/react/platform/bedrock Examples of streaming text responses from Hashbrown Bedrock across different Node.js server frameworks. ```typescript import { HashbrownBedrock } from '@hashbrownai/bedrock'; import express from 'express'; const app = express(); app.use(express.json()); app.post('/chat', async (req, res) => { const stream = HashbrownBedrock.stream.text({ region: process.env.AWS_REGION ?? 'us-east-1', request: req.body, // must be Chat.Api.CompletionCreateParams }); res.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { res.write(chunk); // Pipe each encoded frame as it arrives } res.end(); }); app.listen(3000); ``` ```typescript import { HashbrownBedrock } from '@hashbrownai/bedrock'; import Fastify from 'fastify'; const fastify = Fastify(); fastify.post('/chat', async (request, reply) => { const stream = HashbrownBedrock.stream.text({ region: process.env.AWS_REGION ?? 'us-east-1', request: request.body, // must be Chat.Api.CompletionCreateParams }); reply.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { reply.raw.write(chunk); // Pipe each encoded frame as it arrives } reply.raw.end(); }); fastify.listen({ port: 3000 }); ``` ```typescript import { Controller, Post, Body, Res } from '@nestjs/common'; import { HashbrownBedrock } from '@hashbrownai/bedrock'; import { Response } from 'express'; @Controller() export class ChatController { @Post('chat') async chat(@Body() body: any, @Res() res: Response) { const stream = HashbrownBedrock.stream.text({ region: process.env.AWS_REGION ?? 'us-east-1', request: body, // must be Chat.Api.CompletionCreateParams }); res.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { res.write(chunk); // Pipe each encoded frame as it arrives } res.end(); } } ``` ```typescript import { HashbrownBedrock } from '@hashbrownai/bedrock'; import { Hono } from 'hono'; const app = new Hono(); app.post('/chat', async (c) => { const body = await c.req.json(); const stream = HashbrownBedrock.stream.text({ region: process.env.AWS_REGION ?? 'us-east-1', request: body, // must be Chat.Api.CompletionCreateParams }); return new Response( new ReadableStream({ async start(controller) { for await (const chunk of stream) { controller.enqueue(chunk); // Pipe each encoded frame as it arrives } controller.close(); }, }), { headers: { 'Content-Type': 'application/octet-stream', }, }, ); }); export default app; ``` -------------------------------- ### Define Tool to Get Scenes Source: https://hashbrown.dev/docs/react/recipes/ui-chatbot This hook defines a tool for the LLM to retrieve all available scenes. It requires access to the 'scenes' state from the smart home context. ```javascript import { useTool } from '@hashbrownai/react'; import { useSmartHome } from './smart-home'; export const useGetScenesTool = () => { const { scenes } = useSmartHome(); return useTool({ name: 'getScenes', description: 'Get all available scenes', deps: [scenes], handler: () => { return scenes; }, }); }; ``` -------------------------------- ### Install Hashbrown Angular Dependencies Source: https://hashbrown.dev/docs/angular/recipes/predictive-actions Install the necessary Hashbrown packages for Angular development. Ensure you have Angular 20 or higher. ```bash npm install @hashbrownai/angular @hashbrownai/core @hashbrownai/openai ngx-markdown ``` -------------------------------- ### Configure Client-Side System Instruction Source: https://hashbrown.dev/docs/react/concept/system-instructions Initialize the chat hook with a placeholder indicating that the actual system instruction is managed on the server. ```javascript import { useChat } from '@hashbrownai/react'; const chat = useChat({ system: 'Provided on the server', model: 'gpt-3.5-turbo', }); ``` -------------------------------- ### Compound Values Source: https://hashbrown.dev/docs/angular/concept/schema Examples of defining object and array types in Skillet. ```APIDOC ## Compound Values Skillet allows for the definition of complex data structures like objects and arrays. ### Object ```javascript s.object('A user profile', { name: s.string("The user's name"), age: s.number("The user's age"), active: s.boolean('Whether the user is active'), }); ``` ### Array ```javascript s.array( 'A list of users', s.object('A user', { name: s.string("The user's name"), email: s.string("The user's email"), }), ); ``` ``` -------------------------------- ### Local-First Structured Completion with Fallback Source: https://hashbrown.dev/docs/react/recipes/local-models Use `experimental_local` for on-device model execution, with a cloud fallback like `gpt-5-mini`. The `events` object synchronizes UI with download progress and availability. Retry generation with `reload` after addressing issues like disk space. ```typescript import { useMemo, useState } from 'react'; import { s } from '@hashbrownai/core'; import { experimental_local } from '@hashbrownai/core/transport'; import { useStructuredCompletion } from '@hashbrownai/react'; const ItinerarySchema = s.object('2-day plan', { city: s.string('Destination city'), days: s.streaming.array( 'List of days', s.object('Day', { title: s.streaming.string('Title'), highlights: s.streaming.array( 'Top things to do', s.streaming.string('Activity'), ), }), ), }); export function LocalItinerary() { const [city, setCity] = useState('Lisbon'); const [availability, setAvailability] = useState(null); const [downloadRequired, setDownloadRequired] = useState(false); const [downloadProgress, setDownloadProgress] = useState(null); const input = useMemo( () => (city ? `Plan a concise two-day itinerary for ${city}.` : null), [city], ); const { output, error, isSending, reload } = useStructuredCompletion({ debugName: 'local-itinerary-react', input, system: 'Return a two-day itinerary as JSON that matches the schema.', schema: ItinerarySchema, model: [ experimental_local({ events: { availability: setAvailability, downloadRequired: () => setDownloadRequired(true), downloadProgress: setDownloadProgress, }, }), 'gpt-5-mini', // cloud fallback ], }); return (
setCity(e.target.value)} placeholder="Lisbon" />
Availability: {availability ?? 'checking...'}
{downloadRequired && (
Download required (triggered on first prompt)
)} {downloadProgress !== null &&
Download: {downloadProgress}%
}
{output && (
          {JSON.stringify(output, null, 2)}
        
)} {error &&
Error: {error.message}
}
); } ``` -------------------------------- ### Primitive Values Source: https://hashbrown.dev/docs/angular/concept/schema Examples of how to define primitive data types in Skillet. ```APIDOC ## Primitive Values Skillet supports several primitive data types. ### String ```javascript s.string("The user's full name"); ``` ### Number ```javascript s.number("The user's age in years"); ``` ### Integer ```javascript s.integer('The number of items in the cart'); ``` ### Boolean ```javascript s.boolean('Whether the user account is active'); ``` ### Literal ```javascript s.literal('success'); ``` ``` -------------------------------- ### Define basic smart home tools Source: https://hashbrown.dev/docs/angular/recipes/ui-chatbot Uses createTool to expose service methods to the LLM. The handler runs within the Angular dependency injection context. ```typescript import { inject } from '@angular/core'; import { createTool } from '@hashbrownai/angular'; import { SmartHome } from './smart-home.service'; export const getLights = createTool({ name: 'getLights', description: 'Get all lights and their current state', handler: () => { const smartHome = inject(SmartHome); return smartHome.lights(); }, }); export const getScenes = createTool({ name: 'getScenes', description: 'Get all available scenes', handler: () => { const smartHome = inject(SmartHome); return smartHome.scenes(); }, }); ``` -------------------------------- ### Expected Structured Output Format Source: https://hashbrown.dev/docs/angular/concept/structured-output Example of the JSON object returned by the structured chat resource. ```json { "firstName": "Brian", "lastName": "Love" } ``` -------------------------------- ### Using structuredChatResource() Source: https://hashbrown.dev/docs/angular/concept/structured-output Demonstrates how to create and use a chat resource that parses user input into a structured format based on a provided schema. ```APIDOC ## POST /api/chat/structured ### Description This endpoint facilitates the creation of a chat resource that processes user messages and returns structured data according to a predefined schema. It's particularly useful for replacing traditional forms with natural language interfaces. ### Method POST ### Endpoint /api/chat/structured ### Parameters #### Request Body - **schema** (Schema) - Required - The schema defining the expected structure of the AI's response. This uses Hashbrown's Skillet schema language. - **system** (string) - Required - The system prompt that guides the AI's behavior and response format. - **model** (KnownModelIds | Signal) - Required - Specifies the AI model to be used for processing. - **tools** (Tools[]) - Optional - A list of tools that the AI can utilize. - **messages** (Chat.Message[]) - Optional - An array of initial chat messages to start the conversation. - **debugName** (string) - Optional - A name for debugging purposes. - **debounce** (number) - Optional - The debounce time in milliseconds for processing user input. - **retries** (number) - Optional - The number of times to retry the request in case of failure. - **apiUrl** (string) - Optional - The custom API endpoint URL to use for the request. ### Request Example ```json { "schema": { "type": "object", "properties": { "firstName": { "type": "string", "description": "First name" }, "lastName": { "type": "string", "description": "Last name" } } }, "system": "Collect the user's first and last name.", "model": "gpt-4o" } ``` ### Response #### Success Response (200) - **content** (object) - The structured data parsed from the user's input, conforming to the provided schema. - **firstName** (string) - The user's first name. - **lastName** (string) - The user's last name. #### Response Example ```json { "firstName": "Brian", "lastName": "Love" } ``` ``` -------------------------------- ### Combine and Provide Tools to Hashbrown Chat Source: https://hashbrown.dev/docs/react/recipes/remote-mcp This example demonstrates how to integrate remote MCP tools with local tools within a Hashbrown chat application. It uses `useMcpClient` and `useRemoteMcpTools` to fetch remote tools, `useTool` for local tools, and `useMemo` to combine them before passing to `useChat`. This allows the model to access both sets of functionalities. ```typescript import { useChat, useTool } from '@hashbrownai/react'; import { useMemo } from 'react'; // Example function to fetch user data async function fetchUser({ signal }: { signal?: AbortSignal }) { const response = await fetch('/api/user', { signal }); return response.json(); } function App({ accessToken }: { accessToken: string }) { // 1) Connect to MCP and load remote tools const mcpClientRef = useMcpClient(accessToken); const { remoteTools } = useRemoteMcpTools(mcpClientRef.current); // 2) Define any local React tools with useTool() const getUser = useTool({ name: 'getUser', description: 'Get information about the current user', handler: async (abortSignal) => { return await fetchUser({ signal: abortSignal }); }, deps: [], }); // 3) Combine remote and local tools const tools = useMemo( () => [...remoteTools, getUser], [remoteTools, getUser], ); // 4) Provide tools to the model const chat = useChat({ model: 'gpt-4o', system: 'You are a helpful assistant with access to both local and remote tools.', tools, }); return null; } ``` -------------------------------- ### Define Operational Rules Source: https://hashbrown.dev/docs/angular/concept/system-instructions Example of a structured system instruction block defining behavioral constraints and refusal protocols. ```text ### RULES 1. **Always** answer in 200 words or less unless asked otherwise. 2. If uncertain, **admit it** and offer next steps; do not fabricate. 3. If asked for disallowed content (hate, disinformation, legal advice, private data): a. Respond with: "I'm sorry, but I can't help with that." b. Offer a safer, related alternative if appropriate. ``` -------------------------------- ### Initialize System Prompts Source: https://hashbrown.dev/docs/react/guide/prompt-engineering Sets the model's behavior and persona by passing a string to the system option in the useChat hook. ```typescript import { useChat } from '@hashbrownai/react'; const { messages, sendMessage } = useChat({ model: 'gpt-4', system: `You are a helpful assistant. Answer concisely.`, }); ``` -------------------------------- ### Define Role and Tone Source: https://hashbrown.dev/docs/angular/concept/system-instructions Example of a structured system instruction block defining the assistant's identity and communication style. ```text ### ROLE & TONE You are **ClarityBot**, a seasoned technical-writing assistant. — Voice: concise, friendly, and free of jargon. — Audience: software engineers and product managers. — Attitude: collaborative, playful, never condescending. ``` -------------------------------- ### useUiChat() Source: https://hashbrown.dev/docs/react/concept/components Initializes a UI chat instance with a collection of exposed components. ```APIDOC ## useUiChat(options) ### Description Creates a UI chat instance that allows the model to select and render from a provided collection of exposed components. ### Parameters #### Request Body - **options** (Object) - Required - Configuration object: - **components** (Array) - Required - A collection of exposed components created via exposeComponent(). ### Request Example ```javascript const chat = useUiChat({ components: [ exposeComponent(Markdown, { description: 'Show markdown to the user', props: { data: s.streaming.string('The markdown content'), }, }), ], }); ``` ``` -------------------------------- ### Hashbrown AI SDK vs. Vercel AI SDK Source: https://hashbrown.dev/docs/angular/start/overview A comparison of Hashbrown's AI SDK with Vercel's AI SDK, focusing on their vision, framework support, tooling, streaming capabilities, and UI approach. ```APIDOC ## AI SDK Comparison We love Vercel's AI SDK. We also believe that Hashbrown needs to exist. This is because we want to drastically change the landscape of the web through generative UI. If you have some familiarity with the AI SDK, we hope this quick comparison will be helpful. | Focus | Hashbrown | Vercel AI SDK | | ------------ | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | Vision | Generative UI: models can assemble your actual components. | General AI toolkit: text/JSON outputs with ready-made UI. | | Frameworks | Angular and React first-class. | React/Next.js first-class; also Vue/Svelte. | | Tools | Client-side tool calling + safe WASM sandbox for AI-authored code. | Server-side tool calling. | | Streaming & DX | Binary-normalized streams + Redux DevTools for debugging. | SSE streams with polished hooks; strong Next.js integration. | | UI Approach | AI renders real app components you whitelist. | Developers interpret outputs; AI Elements speeds up chat UI. | ``` -------------------------------- ### Client-Side System Instruction Placeholder Source: https://hashbrown.dev/docs/angular/concept/system-instructions When providing a system instruction on the server, leave the client-side system instruction empty or use it to indicate that it's provided elsewhere. ```javascript chat = chatResource({ system: 'Provided on the server', }); ``` -------------------------------- ### Hono Server Integration with HashbrownAI Source: https://hashbrown.dev/docs/react/platform/azure Integrate HashbrownAI streaming text into a Hono application. This example uses ReadableStream for handling the stream in Hono. ```typescript import { HashbrownAzure } from '@hashbrownai/azure'; import { Hono } from 'hono'; const app = new Hono(); app.post('/chat', async (c) => { const body = await c.req.json(); const stream = HashbrownAzure.stream.text({ apiKey: process.env.AZURE_API_KEY!, endpoint: process.env.AZURE_ENDPOINT!, request: body, // must be Chat.Api.CompletionCreateParams }); return new Response( new ReadableStream({ async start(controller) { for await (const chunk of stream) { controller.enqueue(chunk); // Pipe each encoded frame as it arrives } controller.close(); }, }), { headers: { 'Content-Type': 'application/octet-stream', }, } ); }); export default app; ``` -------------------------------- ### Initialize UI chat with useUiChat Source: https://hashbrown.dev/docs/react/concept/components Creates a chat instance and registers a collection of components that the model can render. ```javascript import { useUiChat, exposeComponent } from '@hashbrownai/react'; import { s } from '@hashbrownai/core'; import { Markdown } from './Markdown'; // 1. Create the UI chat hook const chat = useUiChat({ // 2. Specify the collection of exposed components components: [ // 3. Expose the Markdown component to the model exposeComponent(Markdown, { description: 'Show markdown to the user', props: { data: s.streaming.string('The markdown content'), }, }), ], }); ``` -------------------------------- ### Transform Request Options in Node.js Frameworks Source: https://hashbrown.dev/docs/angular/platform/anthropic Examples of modifying request options using the HashbrownAnthropic client across various Node.js web frameworks. ```typescript import { HashbrownAnthropic } from '@hashbrownai/anthropic'; import express from 'express'; const app = express(); app.use(express.json()); app.post('/chat', async (req, res) => { const stream = HashbrownAnthropic.stream.text({ apiKey: process.env.ANTHROPIC_API_KEY!, request: req.body, transformRequestOptions: (options) => { return { ...options, system: 'You are a helpful assistant.', // prepend server-side system prompt max_tokens: 6000, // override default 4096 }; }, }); res.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { res.write(chunk); } res.end(); }); ``` ```typescript import { HashbrownAnthropic } from '@hashbrownai/anthropic'; import Fastify from 'fastify'; const fastify = Fastify(); fastify.post('/chat', async (request, reply) => { const stream = HashbrownAnthropic.stream.text({ apiKey: process.env.ANTHROPIC_API_KEY!, request: request.body, transformRequestOptions: (options) => ({ ...options, system: 'You are a helpful assistant.', max_tokens: 6000, }), }); reply.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { reply.raw.write(chunk); } reply.raw.end(); }); ``` ```typescript import { Controller, Post, Body, Res } from '@nestjs/common'; import { HashbrownAnthropic } from '@hashbrownai/anthropic'; import { Response } from 'express'; @Controller() export class ChatController { @Post('chat') async chat(@Body() body: any, @Res() res: Response) { const stream = HashbrownAnthropic.stream.text({ apiKey: process.env.ANTHROPIC_API_KEY!, request: body, transformRequestOptions: (options) => ({ ...options, system: 'You are a helpful assistant.', max_tokens: 6000, }), }); res.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { res.write(chunk); } res.end(); } } ``` ```typescript import { HashbrownAnthropic } from '@hashbrownai/anthropic'; import { Hono } from 'hono'; const app = new Hono(); app.post('/chat', async (c) => { const body = await c.req.json(); const stream = HashbrownAnthropic.stream.text({ apiKey: process.env.ANTHROPIC_API_KEY!, request: body, transformRequestOptions: (options) => ({ ...options, system: 'You are a helpful assistant.', max_tokens: 6000, }), }); return new Response( new ReadableStream({ async start(controller) { for await (const chunk of stream) { controller.enqueue(chunk); } controller.close(); }, }), { headers: { 'Content-Type': 'application/octet-stream', }, }, ); }); ``` -------------------------------- ### Modify Request Options in NestJS Source: https://hashbrown.dev/docs/angular/platform/openai Demonstrates modifying request options within a NestJS controller. This example adds a system prompt and customizes the temperature setting. ```typescript import { Controller, Post, Body, Res, Req } from '@nestjs/common'; import { HashbrownOpenAI } from '@hashbrownai/openai'; import { Response, Request } from 'express'; @Controller() export class ChatController { @Post('chat') async chat(@Body() body: any, @Req() req: Request, @Res() res: Response) { const stream = HashbrownOpenAI.stream.text({ apiKey: process.env.OPENAI_API_KEY!, request: body, transformRequestOptions: (options) => { return { ...options, // Add server-side system prompt messages: [ { role: 'system', content: 'You are a helpful assistant.' }, ...options.messages, ], // Adjust temperature based on user preferences temperature: getUserPreferences(req.user.id).creativity, }; }, }); res.header('Content-Type', 'application/octet-stream'); for await (const chunk of stream) { res.write(chunk); } res.end(); } } ``` -------------------------------- ### Initialize UI Chat Resource with Prompt Source: https://hashbrown.dev/docs/angular/concept/components Initializes a UI chat resource using the `prompt` tagged template literal for system instructions. This helps in parsing and validating examples against provided components and their schemas. ```typescript uiChatResource({ // 1. Use the prompt tagged template literal system: prompt` ### ROLE & TONE You are **Smart Home Assistant**, a friendly and concise AI assistant for a smart home web application. - Voice: clear, helpful, and respectful. - Audience: users controlling lights and scenes via the web interface. ### RULES 1. **Never** expose raw data or internal code details. 2. For commands you cannot perform, **admit it** and suggest an alternative. 3. For actionable requests (e.g., changing light settings), **precede** any explanation with the appropriate tool call. ### EXAMPLES Hello `, components: [ exposeComponent(MarkdownComponent, { ... }) ] }); ``` -------------------------------- ### Initialize Angular Chat Resource with Thread ID Source: https://hashbrown.dev/docs/angular/recipes/threads Pass a threadId to the uiChatResource to rehydrate an existing conversation or start a new one that supports delta updates. ```typescript import { uiChatResource } from '@hashbrownai/angular'; const chat = uiChatResource({ model: 'gpt-4.1', threadId: 'a06c6efd-6e1d-428b-8419-1fb04538b6b2', // existing chat to rehydrate system: 'You are a helpful assistant for a smart home app.', components: [ /* exposed UI components */ ], tools: [ /* createTool(...) definitions */ ], }); ``` -------------------------------- ### Managing User Input in System Instructions Source: https://hashbrown.dev/docs/angular/concept/system-instructions Compares insecure direct concatenation of user input with the recommended approach of passing input via structured objects. ```javascript completionResource({ system: ` Help the user autocomplete this input. So far they have typed in: ${names().join(', ')} `, input: textInputValue, }); ``` ```javascript completionResource({ system: ` Help the user autocomplete this input. `, input: computed(() => ({ currentValue: textInputValue(), previousNames: names(), })), }); ```