Skip to content

Instantly share code, notes, and snippets.

@dabit3
Last active April 13, 2025 23:17
Show Gist options
  • Save dabit3/8be495be73ba520b62cd8fbadffce665 to your computer and use it in GitHub Desktop.
Save dabit3/8be495be73ba520b62cd8fbadffce665 to your computer and use it in GitHub Desktop.
Verifiable AI Inference AVS prompt using OpenAI Using WAVS - https://docs.wavs.xyz/overview

Create an OpenAI inference component based on the ETH Price Oracle (components/eth-price-oracle). The component should:

  1. Accept input in the format 'PROMPT|OPENAI_API_KEY|SEED' from a Makefile parameter
  2. Use fetch_json and http_request_post_json for API communication
  3. Return and log only choices[0].message.content and choices[0].finish_reason
  4. Include proper input validation and SEED should be an integer
  5. Use the main makefile, do not create a separate one.

Important Implementation Details:

  • Create proper serializable structs for the request payload
  • CRITICAL: Pass the request struct DIRECTLY to http_request_post_json, NOT a serialized string or byte array
  • Use #[derive(Debug, Serialize)] for request structures and #[derive(Debug, Deserialize)] for response structures
  • For OpenAIResponse, do NOT use #[serde(flatten)] on the error field
  • Use serde_json::Value for the message field in the Choice struct to flexibly handle the message format
  • For logging, use crate::bindings::host::log and crate::bindings::host::LogLevel instead of direct host imports
  • For setting headers, look at how the eth-price-oracle component does this with http_request_get().headers_mut().insert() pattern
  • Implement safe response parsing using .get() and .and_then() methods
  • Check for API errors in the response before attempting to extract content
  • Implement Display trait for OpenAIResponseData struct to enable proper logging
  • Be sure to include the "Accept" header in addition to "Content-Type" and "Authorization"

The API request structure is:

{
  "seed": $SEED,
  "model": "gpt-4o",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "<PROMPT>"}
  ]
}

The API response will be deserialized into a struct like this:

  #[derive(Debug, Deserialize)]
  struct OpenAIResponse {
      id: Option<String>,
      model: Option<String>,
      choices: Vec<OpenAIChoice>,
      error: Option<OpenAIError>,  // NOT flattened
  }

  #[derive(Debug, Deserialize)]
  struct OpenAIChoice {
      message: serde_json::Value,  // Use Value for flexibility
      finish_reason: Option<String>,
  }

Authorization header should be added to the request using:

  req.headers_mut().insert(
      "Authorization",
      HeaderValue::from_str(&format!("Bearer {}", api_key)).map_err(|e| e.to_string())?,
  );

The Makefile command should be:

  ai-exec:
      @$(WAVS_CMD) exec --log-level=info --data /data/.docker --home /data \
      --component "/data/compiled/${AI_COMPONENT_FILENAME}" \
      --input "$(PROMPT)|$(OPENAI_API_KEY)|$(SEED)"

Implement logging that shows request details (but not the API key) and response structure for debugging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment