ST

streaming-chat

Handles streaming AI chatbot inference via the 0G Compute Network.

Install

mkdir -p .claude/skills/streaming-chat && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16750" && unzip -o skill.zip -d .claude/skills/streaming-chat && rm skill.zip

Installs to .claude/skills/streaming-chat

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

- **Category**: compute - **SDK**: `@0glabs/0g-serving-broker` ^0.6.5, `ethers` ^6.13.0 - **Activation Triggers**: "chatbot", "inference", "LLM", "DeepSeek", "streaming chat", "AI chat"
185 chars · catalog descriptionno explicit “when” trigger
Intermediate

Key capabilities

  • Initialize a broker for 0G Compute Network
  • Obtain service metadata for inference
  • Generate authentication headers for requests
  • Make chat completion requests to LLM providers
  • Process responses for fee settlement

How it works

The skill initializes a broker, retrieves service metadata, generates auth headers, sends a chat completion request to an LLM provider, and critically processes the response for fee settlement.

Inputs & outputs

You give it
A user message for conversational AI inference
You get back
A streaming or non-streaming response from an LLM, with fee settlement processed

When to use streaming-chat

  • Run chatbot inference
  • Stream AI model responses
  • Integrate DeepSeek V3.1

About this skill

Streaming Chat Inference

Metadata

  • Category: compute
  • SDK: @0glabs/0g-serving-broker ^0.6.5, ethers ^6.13.0
  • Activation Triggers: "chatbot", "inference", "LLM", "DeepSeek", "streaming chat", "AI chat"

Purpose

Run conversational AI inference using 0G Compute Network providers. Supports streaming and non-streaming modes with models like DeepSeek V3.1, Qwen, Gemma, and GPT-OSS.

Prerequisites

  • Node.js >= 22
  • @0glabs/0g-serving-broker and ethers installed
  • Funded and acknowledged provider
  • .env with PRIVATE_KEY, RPC_URL, PROVIDER_ADDRESS

Quick Workflow

  1. Initialize broker
  2. Get service metadata (endpoint, model)
  3. Generate auth headers
  4. Make chat completion request
  5. Extract ChatID from ZG-Res-Key header (body fallback)
  6. Call processResponse(providerAddress, chatID, usageData) — CRITICAL

Core Rules

ALWAYS

  • Call processResponse() after EVERY inference request
  • Use correct param order: processResponse(providerAddress, chatID, usageData)
  • Extract ChatID from ZG-Res-Key header FIRST, use data.id as fallback (chatbot only)
  • Acknowledge provider before first use
  • Check balance before making requests

NEVER

  • Skip processResponse() — causes fee settlement failure
  • Reverse the parameter order of processResponse()
  • Hardcode private keys
  • Use ethers v5 syntax

Code Examples

Non-Streaming Chat

import { ethers } from 'ethers';
import { createZGComputeNetworkBroker } from '@0glabs/0g-serving-broker';
import 'dotenv/config';

async function chat(userMessage: string): Promise<string> {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
  const broker = await createZGComputeNetworkBroker(wallet);

  const providerAddress = process.env.PROVIDER_ADDRESS!;
  const { endpoint, model } = await broker.inference.getServiceMetadata(providerAddress);
  const headers = await broker.inference.getRequestHeaders(providerAddress);

  const messages = [{ role: 'user', content: userMessage }];

  const response = await fetch(`${endpoint}/chat/completions`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', ...headers },
    body: JSON.stringify({ messages, model }),
  });

  const data = await response.json();
  const answer = data.choices[0].message.content;

  // CRITICAL: Process response for fee settlement
  let chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
  if (!chatID) chatID = data.id; // Fallback for chatbot

  await broker.inference.processResponse(providerAddress, chatID, JSON.stringify(data.usage));

  return answer;
}

// Usage
const reply = await chat('What is 0G?');
console.log(reply);

Streaming Chat

async function streamingChat(userMessage: string): Promise<string> {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
  const broker = await createZGComputeNetworkBroker(wallet);

  const providerAddress = process.env.PROVIDER_ADDRESS!;
  const { endpoint, model } = await broker.inference.getServiceMetadata(providerAddress);
  const headers = await broker.inference.getRequestHeaders(providerAddress);

  const messages = [{ role: 'user', content: userMessage }];

  const response = await fetch(`${endpoint}/chat/completions`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', ...headers },
    body: JSON.stringify({ messages, model, stream: true }),
  });

  // ChatID from header (primary source)
  let chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
  let usage = null;
  let streamChatID = null;
  let fullResponse = '';

  const decoder = new TextDecoder();
  const reader = response.body!.getReader();
  let rawBody = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const chunk = decoder.decode(value, { stream: true });
    rawBody += chunk;
    process.stdout.write(chunk); // Real-time output
  }

  // Parse stream for fallback chatID and usage data
  for (const line of rawBody.split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed === 'data: [DONE]') continue;
    try {
      const jsonStr = trimmed.startsWith('data:') ? trimmed.slice(5).trim() : trimmed;
      const message = JSON.parse(jsonStr);
      if (!streamChatID && message.id) streamChatID = message.id;
      if (message.usage) usage = message.usage;
      if (message.choices?.[0]?.delta?.content) {
        fullResponse += message.choices[0].delta.content;
      }
    } catch {}
  }

  // CRITICAL: processResponse with correct param order
  const finalChatID = chatID || streamChatID;
  await broker.inference.processResponse(providerAddress, finalChatID, JSON.stringify(usage || {}));

  return fullResponse;
}

Multi-Turn Conversation

async function conversation() {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
  const broker = await createZGComputeNetworkBroker(wallet);

  const providerAddress = process.env.PROVIDER_ADDRESS!;
  const { endpoint, model } = await broker.inference.getServiceMetadata(providerAddress);

  const history: Array<{ role: string; content: string }> = [
    { role: 'system', content: 'You are a helpful assistant.' },
  ];

  async function sendMessage(userMessage: string): Promise<string> {
    history.push({ role: 'user', content: userMessage });

    const headers = await broker.inference.getRequestHeaders(providerAddress);
    const response = await fetch(`${endpoint}/chat/completions`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', ...headers },
      body: JSON.stringify({ messages: history, model }),
    });

    const data = await response.json();
    const answer = data.choices[0].message.content;
    history.push({ role: 'assistant', content: answer });

    let chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
    if (!chatID) chatID = data.id;

    await broker.inference.processResponse(providerAddress, chatID, JSON.stringify(data.usage));

    return answer;
  }

  const reply1 = await sendMessage('What is 0G?');
  console.log('Assistant:', reply1);

  const reply2 = await sendMessage('Tell me more about its storage layer.');
  console.log('Assistant:', reply2);
}

Error Handling

async function resilientChat(userMessage: string, maxRetries = 3): Promise<string> {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
  const broker = await createZGComputeNetworkBroker(wallet);

  const providerAddress = process.env.PROVIDER_ADDRESS!;
  const { endpoint, model } = await broker.inference.getServiceMetadata(providerAddress);

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const headers = await broker.inference.getRequestHeaders(providerAddress);
      const response = await fetch(`${endpoint}/chat/completions`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...headers },
        body: JSON.stringify({ messages: [{ role: 'user', content: userMessage }], model }),
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${await response.text()}`);
      }

      const data = await response.json();
      const answer = data.choices[0].message.content;

      let chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
      if (!chatID) chatID = data.id;

      await broker.inference.processResponse(providerAddress, chatID, JSON.stringify(data.usage));

      return answer;
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error);
      if (attempt === maxRetries) throw error;
      await new Promise((r) => setTimeout(r, 1000 * attempt));
    }
  }

  throw new Error('All retries exhausted');
}

Anti-Patterns

// BAD: Missing processResponse — fee settlement failure
const data = await response.json();
return data.choices[0].message.content;
// processResponse() never called!

// BAD: Wrong parameter order
await broker.inference.processResponse(
  chatID, // WRONG — should be providerAddress
  providerAddress, // WRONG — should be chatID
  usage,
);

// BAD: Using body ID without checking header first
const chatID = data.id; // Should check ZG-Res-Key header first!

// BAD: ethers v5 syntax
const provider = new ethers.providers.JsonRpcProvider(url); // v5!

// BAD: Hardcoding private keys
const wallet = new ethers.Wallet('0xabc123...', provider); // NEVER do this

Common Errors & Fixes

ErrorCauseFix
Insufficient balanceSub-account emptyTransfer funds to provider
Provider not acknowledgedFirst-time provideracknowledgeProviderSigner()
Invalid request headersStale auth headersRe-call getRequestHeaders()
Fee verification failedWrong processResponse paramsCheck param order and chatID
stream errorNetwork interruptionImplement retry logic

Related Skills

References

When not to use it

  • When interacting with LLM providers outside the 0G Compute Network
  • When not requiring streaming or non-streaming chat inference

Prerequisites

Node.js >= 22`@0glabs/0g-serving-broker` installed`ethers` installedFunded and acknowledged provider

Limitations

  • The skill is specific to the 0G Compute Network and its providers.
  • The skill requires explicit calls to `processResponse()` for fee settlement.

How it compares

This skill manages the entire lifecycle of an LLM inference request on the 0G Compute Network, including authentication and fee settlement, which is more integrated than directly calling an LLM API.

Compared to similar skills

streaming-chat side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
streaming-chat (this skill)04moReviewIntermediate
agentscope-java12moNo flagsAdvanced
ai-model-nodejs52moReviewIntermediate
Video Generation03moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

agentscope-java

agentscope-ai

Expert Java developer skill for AgentScope Java framework - a reactive, message-driven multi-agent system built on Project Reactor. Use when working with reactive programming, LLM integration, agent orchestration, multi-agent systems, or when the user mentions AgentScope, ReActAgent, Mono/Flux, Project Reactor, or Java agent development. Specializes in non-blocking code, tool integration, hooks, pipelines, and production-ready agent applications.

122

ai-model-nodejs

TencentCloudBase

Use this skill when developing Node.js backend services or CloudBase cloud functions (Express/Koa/NestJS, serverless, backend APIs) that need AI capabilities. Features text generation (generateText), streaming (streamText), AND image generation (generateImage) via @cloudbase/node-sdk ≥3.16.0. Built-in models include Hunyuan (hunyuan-2.0-instruct-20251111 recommended), DeepSeek (deepseek-v3.2 recommended), and hunyuan-image for images. This is the ONLY SDK that supports image generation. NOT for browser/Web apps (use ai-model-web) or WeChat Mini Program (use ai-model-wechat).

59

Video Generation

e2662020

Implement AI-powered video generation capabilities using the z-ai-web-dev-sdk. Use this skill when the user needs to generate videos from text prompts or images, create video content programmatically, or build applications that produce video outputs. Supports asynchronous task management with status

00

add-ai-endpoint

malhajri07

Scaffold a Claude API powered endpoint with system prompt, structured output, token tracking, and rate limiting. Use when adding AI features like chatbot, matching, or text generation.

00

supabase-developer

daffy0208

Build full-stack applications with Supabase (PostgreSQL, Auth, Storage, Real-time, Edge Functions). Use when implementing authentication, database design with RLS, file storage, real-time features, or serverless functions.

95185

architecture-patterns

wshobson

Implement proven backend architecture patterns including Clean Architecture, Hexagonal Architecture, and Domain-Driven Design. Use when architecting complex backend systems or refactoring existing applications for better maintainability.

55214

Search skills

Search the agent skills registry