Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/lint-code-examples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Lint Code Examples

on:
pull_request:
paths:
- 'pages/**/*.mdx'
- 'scripts/lint-code-examples.py'
push:
branches: [main]
paths:
- 'pages/**/*.mdx'
- 'scripts/lint-code-examples.py'
Comment on lines +4 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Include this workflow file in its own path filters.

A PR that only changes .github/workflows/lint-code-examples.yml will not run this job today, so workflow regressions can merge without ever exercising the updated definition.

Suggested fix
 on:
   pull_request:
     paths:
+      - '.github/workflows/lint-code-examples.yml'
       - 'pages/**/*.mdx'
       - 'scripts/lint-code-examples.py'
   push:
     branches: [main]
     paths:
+      - '.github/workflows/lint-code-examples.yml'
       - 'pages/**/*.mdx'
       - 'scripts/lint-code-examples.py'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pull_request:
paths:
- 'pages/**/*.mdx'
- 'scripts/lint-code-examples.py'
push:
branches: [main]
paths:
- 'pages/**/*.mdx'
- 'scripts/lint-code-examples.py'
on:
pull_request:
paths:
- '.github/workflows/lint-code-examples.yml'
- 'pages/**/*.mdx'
- 'scripts/lint-code-examples.py'
push:
branches: [main]
paths:
- '.github/workflows/lint-code-examples.yml'
- 'pages/**/*.mdx'
- 'scripts/lint-code-examples.py'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/lint-code-examples.yml around lines 4 - 12, Add the
workflow file itself to the path filters so changes to
.github/workflows/lint-code-examples.yml will trigger the job; specifically
update the pull_request.paths and push.paths lists in the workflow to include
'.github/workflows/lint-code-examples.yml' alongside 'pages/**/*.mdx' and
'scripts/lint-code-examples.py' (edit the paths section around the existing
entries in the lint-code-examples job).


jobs:
lint-code-examples:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install genvm-linter
- run: python scripts/lint-code-examples.py
2 changes: 1 addition & 1 deletion pages/api-references/genlayer-test.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ assert default_account != other_account
For the following code examples, we'll use a Storage Intelligent Contract as a reference:

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *

Expand Down
9 changes: 5 additions & 4 deletions pages/developers/intelligent-contracts/crafting-prompts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ When crafting prompts for LLMs, it's important to use a format that clearly and
In the example **Wizard of Coin** contract below, we want the LLM to decide whether the wizard should give the coin to an adventurer.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
from genlayer import *

import json
Expand Down Expand Up @@ -55,13 +55,14 @@ This result should be perfectly parseable by a JSON parser without errors.
"""

def nondet():
res = gl.exec_prompt(prompt)
res = res.replace("```json", "").replace("```", "")
res = gl.nondet.exec_prompt(prompt)
backticks = "``" + "`"
res = res.replace(backticks + "json", "").replace(backticks, "")
Comment on lines +58 to +60
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import json

def current(res: str) -> str:
    backticks = "``" + "`"
    return res.replace(backticks + "json", "").replace(backticks, "")

samples = {
    "lowercase json": "```json\n{\"give_coin\": false}\n```",
    "uppercase JSON": "```JSON\n{\"give_coin\": false}\n```",
    "space after fence": "``` json\n{\"give_coin\": false}\n```",
    "bare fence": "```\n{\"give_coin\": false}\n```",
}

for name, sample in samples.items():
    cleaned = current(sample)
    try:
        json.loads(cleaned)
        verdict = "parses"
    except Exception as exc:
        verdict = f"fails: {exc}"
    print(f"{name}: {verdict}")
PY

Repository: genlayerlabs/genlayer-docs

Length of output: 244


🏁 Script executed:

fd crafting-prompts.mdx --type f

Repository: genlayerlabs/genlayer-docs

Length of output: 129


🏁 Script executed:

cat -n pages/developers/intelligent-contracts/crafting-prompts.mdx | sed -n '50,70p'

Repository: genlayerlabs/genlayer-docs

Length of output: 953


Strip only surrounding code fences before json.loads.

The current implementation only handles the exact lowercase ```json case. Testing against common LLM output variants shows:

  • uppercase JSON: fails with Expecting value: line 1 column 1
  • space after fence (``` json): fails with Expecting value: line 1 column 2
  • bare fence: parses (only by accident)
  • lowercase json: parses

This will cause the documented example to fail at runtime on typical LLM outputs.

Proposed fix
         def nondet():
             res = gl.nondet.exec_prompt(prompt)
-            backticks = "``" + "`"
-            res = res.replace(backticks + "json", "").replace(backticks, "")
+            res = res.strip()
+            if res.startswith("```"):
+                lines = res.splitlines()
+                if lines:
+                    lines = lines[1:]
+                if lines and lines[-1].strip() == "```":
+                    lines = lines[:-1]
+                res = "\n".join(lines).strip()
             print(res)
             dat = json.loads(res)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/developers/intelligent-contracts/crafting-prompts.mdx` around lines 58
- 60, The output from gl.nondet.exec_prompt stored in res must have only the
surrounding code-fence removed before calling json.loads; update the handling
around res (after the call to gl.nondet.exec_prompt and before json.loads) to
robustly strip a leading fence line (any line that starts with "```" optionally
followed by a language tag, case-insensitive, and optional spaces) and a
trailing fence line (a line that after stripping whitespace equals "```"), by
splitting res into lines, dropping the first line if it startswith "```"
(case-insensitive check) and dropping the last line if its stripped form is
"```", then rejoin and strip the result before passing to json.loads; keep
references to res, gl.nondet.exec_prompt, and json.loads so the change is easy
to locate.

print(res)
dat = json.loads(res)
return dat["give_coin"]

result = gl.eq_principle_strict_eq(nondet)
result = gl.eq_principle.strict_eq(nondet)
assert isinstance(result, bool)
self.have_coin = result

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The FetchGitHubProfile contract demonstrates how to fetch and store GitHub profile content within an intelligent contract. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) to ensure all nodes agree on the same profile content.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *
import typing
Expand All @@ -20,9 +20,10 @@ class FetchGitHubProfile(gl.Contract):
github_profile_url = "https://github.com/"+github_handle

def fetch_github_profile_page_content() -> str:
return gl.get_webpage(github_profile_url, mode="text")

self.github_profile = gl.eq_principle_strict_eq(fetch_github_profile_page_content)
response = gl.nondet.web.get(github_profile_url)
return response.body.decode("utf-8")

self.github_profile = gl.eq_principle.strict_eq(fetch_github_profile_page_content)

@gl.public.view
def show_github_profile(self) -> str:
Expand All @@ -35,14 +36,14 @@ class FetchGitHubProfile(gl.Contract):
- **Write Method**:
- `fetch_github_profile(github_handle)` takes a GitHub username and retrieves their profile content.
- Constructs the profile URL using the provided handle.
- Uses `gl.eq_principle_strict_eq()` to ensure all nodes agree on the same profile content.
- Uses `gl.eq_principle.strict_eq()` to ensure all nodes agree on the same profile content.
- **Read Method**:
- `show_github_profile()` returns the stored profile content.

## Key Components

1. **GitHub Integration**: The contract uses `gl.get_webpage()` to fetch content from GitHub profiles.
2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact content.
1. **GitHub Integration**: The contract uses `gl.nondet.web.get()` to fetch content from GitHub profiles.
2. **Deterministic Execution**: `gl.eq_principle.strict_eq()` ensures that all nodes in the network arrive at the same exact content.
Comment on lines +39 to +46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Finish the terminology update across the whole page.

This section now documents gl.eq_principle.strict_eq(), but the page still has stale references to the old behavior: Line 3 says the example uses the comparative equivalence principle, and Line 95 still mentions the removed mode="text" parameter. That leaves the example internally inconsistent for readers.

🧰 Tools
🪛 LanguageTool

[style] ~46-~46: This phrase is redundant. Consider writing “same”.
Context: ... all nodes in the network arrive at the same exact content. 3. State Management: The c...

(SAME_EXACT)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/developers/intelligent-contracts/examples/fetch-github-profile.mdx`
around lines 39 - 46, Update the page to complete the terminology change from
the "comparative equivalence principle" to the current API name
gl.eq_principle.strict_eq(): replace any text mentions of the old phrase with
gl.eq_principle.strict_eq() and adjust surrounding wording to match the
deterministic-equivalence framing used elsewhere; remove the stale mention of
the removed parameter mode="text" (and any example calls to gl.nondet.web.get()
that include it) and ensure examples and the show_github_profile() read method
description consistently reference gl.nondet.web.get() +
gl.eq_principle.strict_eq() semantics only.

3. **State Management**: The contract maintains a single string state variable that stores the profile content.

## Deploying the Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The FetchWebContent contract demonstrates how to fetch and store web content within an intelligent contract. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) to ensure all nodes agree on the same web content.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *
import typing
Expand All @@ -19,9 +19,10 @@ class FetchWebContent(gl.Contract):
def fetch_web_content(self) -> typing.Any:

def fetch_web_url_content() -> str:
return gl.get_webpage("https://example.com/", mode="text")

self.content = gl.eq_principle_strict_eq(fetch_web_url_content)
response = gl.nondet.web.get("https://example.com/")
return response.body.decode("utf-8")

self.content = gl.eq_principle.strict_eq(fetch_web_url_content)

@gl.public.view
def show_content(self) -> str:
Expand All @@ -33,15 +34,15 @@ class FetchWebContent(gl.Contract):
- **Initialization**: The `FetchWebContent` class initializes with an empty string in the `content` variable.
- **Write Method**:
- `fetch_web_content()` retrieves content from a web page and stores it.
- It contains an inner function `fetch_web_url_content()` that uses `gl.get_webpage()` to fetch content.
- Uses `gl.eq_principle_strict_eq()` to ensure all nodes agree on the same content.
- It contains an inner function `fetch_web_url_content()` that uses `gl.nondet.web.get()` to fetch content.
- Uses `gl.eq_principle.strict_eq()` to ensure all nodes agree on the same content.
- **Read Method**:
- `show_content()` returns the stored web content.

## Key Components

1. **Web Integration**: The contract uses `gl.get_webpage()` to fetch content from web URLs.
2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact content.
1. **Web Integration**: The contract uses `gl.nondet.web.get()` to fetch content from web URLs.
2. **Deterministic Execution**: `gl.eq_principle.strict_eq()` ensures that all nodes in the network arrive at the same exact content.
3. **State Management**: The contract maintains a single string state variable that stores the web content.

## Deploying the Contract
Expand Down Expand Up @@ -101,7 +102,7 @@ You can monitor the contract's behavior through transaction logs, which will sho

## HTML Mode for Web Content

The `gl.get_webpage()` function supports different modes for retrieving web content. While `mode="text"` returns the plain text content, `mode="html"` allows you to retrieve the complete HTML `<body>` of the webpage.
The `gl.nondet.web.get()` function supports different modes for retrieving web content. While the default mode returns the plain text content, `gl.nondet.web.render()` with `mode="html"` allows you to retrieve the complete HTML `<body>` of the webpage.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

According to the latest GenLayer documentation, does gl.nondet.web.render(..., mode="html")return the full HTML document or only the rendered, and is mode="text"still a supported parameter forgl.nondet.web.get()?

💡 Result:

  • gl.nondet.web.render(..., mode="html"): The latest GenLayer SDK docs describe this as returning the rendered webpage “HTML content” as a str, but they do not specify that it’s only the rendered <body> (vs. a full serialized HTML document). In the current SDK implementation, both mode="html" and mode="text" return a string from the same decoded text field, without any documented/visible “body-only” extraction step. [1], [2]

  • mode="text" on gl.nondet.web.get(): Nogl.nondet.web.get(url, headers=...) does not take a mode parameter in the latest SDK; it only returns a Response (status/headers/body). The "text"/"html" modes apply to gl.nondet.web.render(), not get(). [1], [2]

Sources:
[1] GenLayer SDK API docs (gl.nondet.web.get, gl.nondet.web.render) — https://sdk.genlayer.com/main/api/genlayer.html
[2] GenLayer SDK source for genlayer.gl.nondet.webhttps://sdk.genlayer.com/main/_modules/genlayer/gl/nondet/web.html


🏁 Script executed:

cat -n pages/developers/intelligent-contracts/examples/fetch-web-content.mdx | sed -n '85,135p'

Repository: genlayerlabs/genlayer-docs

Length of output: 2433


Fix conflicting API documentation about mode parameters and HTML output scope.

The file contains two contradictory statements:

  1. Line 92 mentions mode="text" as a parameter for the preceding examples, but according to GenLayer SDK documentation, mode parameters apply only to gl.nondet.web.render(), not gl.nondet.web.get(), making this note misleading.
  2. Line 105 states mode="html" returns the <body>, but Line 130 states it returns the "full HTML document"—these descriptions are incompatible.

Update Line 92 to accurately reflect which functions support mode parameters, and align Lines 105 and 130 to consistently describe what mode="html" actually returns.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/developers/intelligent-contracts/examples/fetch-web-content.mdx` at
line 105, Update the docs to state that mode parameters apply only to
gl.nondet.web.render(), not gl.nondet.web.get(); clarify that
gl.nondet.web.get() returns plain text by default and remove the misleading
reference to mode="text" for the get() examples, and make both occurrences
describing mode="html" (the ones referencing mode="html" and the "full HTML
document") consistent by saying mode="html" for gl.nondet.web.render() returns
the page's HTML <body> (not the entire document or other scope).


Here's an example of using HTML mode:

Expand All @@ -115,9 +116,9 @@ class FetchHTMLContent(gl.Contract):
@gl.public.write
def fetch_html_content(self) -> typing.Any:
def fetch_web_url_html() -> str:
return gl.get_webpage("https://example.com/", mode="html")
self.html_content = gl.eq_principle_strict_eq(fetch_web_url_html)
return gl.nondet.web.render("https://example.com/", mode='html')

self.html_content = gl.eq_principle.strict_eq(fetch_web_url_html)

@gl.public.view
def show_html_content(self) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The GitHubProfilesRepositories contract demonstrates how to fetch GitHub profile data, analyze repository counts, and store profiles of high-contributing developers. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) along with pattern matching to process web content.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *
import typing
Expand All @@ -20,7 +20,8 @@ class GitHubProfilesRepositories(gl.Contract):
github_profile_url = "https://github.com/"+github_handle

def fetch_github_profile_repositories() -> int:
profile_web_page = gl.get_webpage(github_profile_url, mode="text")
response = gl.nondet.web.get(github_profile_url)
profile_web_page = response.body.decode("utf-8")
# Regular expression to find the number between "Repositories" and "Projects"
pattern = r"Repositories\s+(\d+)\s+Projects"

Expand All @@ -33,7 +34,7 @@ class GitHubProfilesRepositories(gl.Contract):
else:
return 0

repositories = gl.eq_principle_strict_eq(fetch_github_profile_repositories)
repositories = gl.eq_principle.strict_eq(fetch_github_profile_repositories)

if repositories > 25:
self.github_profiles.append(github_handle)
Expand All @@ -55,9 +56,9 @@ class GitHubProfilesRepositories(gl.Contract):

## Key Components

1. **GitHub Integration**: Uses `gl.get_webpage()` to fetch profile content.
1. **GitHub Integration**: Uses `gl.nondet.web.get()` to fetch profile content.
2. **Pattern Matching**: Employs regular expressions to extract repository counts.
3. **Deterministic Execution**: Uses `gl.eq_principle_strict_eq()` to ensure network consensus.
3. **Deterministic Execution**: Uses `gl.eq_principle.strict_eq()` to ensure network consensus.
4. **Conditional Storage**: Only stores profiles meeting specific criteria.

## Deploying the Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The GitHubProfilesSummaries contract demonstrates how to fetch GitHub profile data and generate AI-powered summaries of user profiles. This contract shows how to combine web scraping with AI analysis using both [comparative](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) and [non-comparative](/developers/intelligent-contracts/equivalence-principle#non-comparative-equivalence-principle) equivalence principles.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *
import typing
Expand All @@ -25,17 +25,18 @@ class GitHubProfilesSummaries(gl.Contract):
github_profile_url = "https://github.com/"+github_handle

def fetch_github_profile_summaries() -> str:
return gl.get_webpage(github_profile_url, mode="text")
response = gl.nondet.web.get(github_profile_url)
return response.body.decode("utf-8")

profile_content = gl.eq_principle_strict_eq(fetch_github_profile_summaries)
profile_content = gl.eq_principle.strict_eq(fetch_github_profile_summaries)

task = """Given the web page content of a github profile in HTML format, generate a comprehensive
summary of the profile mentioning the key meta attributes and the GitHub contribution most important metrics"""

criteria = """The summary provided should include different metrics and a summary of a GitHub profile"""

profile_summary = (
gl.eq_principle_prompt_non_comparative(
gl.eq_principle.prompt_non_comparative(
lambda: profile_content,
task=task,
criteria=criteria,
Expand All @@ -61,7 +62,7 @@ summary of the profile mentioning the key meta attributes and the GitHub contrib
## Key Components

1. **Data Storage**: Uses `TreeMap` for efficient key-value storage of profile summaries.
2. **Web Fetching**: Uses `gl.get_webpage()` with strict equivalence for deterministic content retrieval.
2. **Web Fetching**: Uses `gl.nondet.web.get()` with strict equivalence for deterministic content retrieval.
3. **AI Analysis**: Uses non-comparative equivalence for generating profile summaries.
4. **Duplicate Prevention**: Includes checks to prevent regenerating existing summaries.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The LlmHelloWorldNonComparative contract demonstrates a simple example of integrating AI capabilities within an intelligent contract without requiring that all the validators execute the full task. They just need to evaluate the leader's response against the specified criteria. This is done by using the [non-comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#non-comparative-equivalence-principle).

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *
import typing
Expand All @@ -17,7 +17,7 @@ class LlmHelloWorldNonComparative(gl.Contract):

@gl.public.write
def set_message(self) -> typing.Any:
self.message = gl.eq_principle_prompt_non_comparative(
self.message = gl.eq_principle.prompt_non_comparative(
lambda: "There is no context, I just want you to answer with truthy value in python (for example: 'yes', 'True', 1)",
task="Answer with truthy value in python (for example: 'yes', 'True', 1)",
criteria="Answer should be a truthy value in python"
Expand All @@ -33,7 +33,7 @@ class LlmHelloWorldNonComparative(gl.Contract):
- **Initialization**: The `LlmHelloWorldNonComparative` class initializes with an empty string in the `message` variable.
- **Write Method**:
- `set_message()` uses AI functionality to generate and store a message.
- Uses `gl.eq_principle_prompt_non_comparative()` with three parameters:
- Uses `gl.eq_principle.prompt_non_comparative()` with three parameters:
- A lambda function providing the prompt
- A task description
- Validation criteria for the response
Expand All @@ -43,7 +43,7 @@ class LlmHelloWorldNonComparative(gl.Contract):
## Key Components

1. **AI Integration**: The contract uses non-comparative equivalence principle to interact with an AI model.
2. **Deterministic Execution**: `gl.eq_principle_prompt_non_comparative()` ensures that all nodes in the network accept responses that meet the specified criteria.
2. **Deterministic Execution**: `gl.eq_principle.prompt_non_comparative()` ensures that all nodes in the network accept responses that meet the specified criteria.
3. **State Management**: The contract maintains a single string state variable that stores the AI response.

## Deploying the Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The LlmHelloWorld contract demonstrates a simple example of integrating AI capabilities within an intelligent contract. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) to call an LLM and store the response in the contract state.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *
import typing
Expand All @@ -20,11 +20,11 @@ class LlmHelloWorld(gl.Contract):

def get_message() -> str:
task = "There is no context, I just want you to answer with a string equal to 'yes'"
result = gl.exec_prompt(task)
result = gl.nondet.exec_prompt(task)
print(result)
return result

self.message = gl.eq_principle_strict_eq(get_message)
self.message = gl.eq_principle.strict_eq(get_message)

@gl.public.view
def get_message(self) -> str:
Expand All @@ -37,14 +37,14 @@ class LlmHelloWorld(gl.Contract):
- **Write Method**:
- `set_message()` uses AI functionality to generate and store a message.
- It contains an inner function `get_message()` that prompts an AI model with a simple task.
- Uses `gl.eq_principle_strict_eq()` to ensure deterministic AI responses across the network.
- Uses `gl.eq_principle.strict_eq()` to ensure deterministic AI responses across the network.
- **Read Method**:
- `get_message()` returns the stored message.

## Key Components

1. **AI Integration**: The contract uses `gl.exec_prompt()` to interact with an AI model.
2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact result.
1. **AI Integration**: The contract uses `gl.nondet.exec_prompt()` to interact with an AI model.
2. **Deterministic Execution**: `gl.eq_principle.strict_eq()` ensures that all nodes in the network arrive at the same exact result.
3. **State Management**: The contract maintains a single string state variable that stores the AI response.

## Deploying the Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The Prediction Market contract sets up a scenario to determine the outcome of a football game between two teams. The contract uses the Equivalence Principle to ensure accurate and consistent decision-making based on the game's resolution data.

```python filename="PredictionMarket" copy
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *

Expand Down Expand Up @@ -49,7 +49,8 @@ class PredictionMarket(gl.Contract):
return "Already resolved"

def nondet() -> str:
web_data = gl.get_webpage(self.resolution_url, mode="text")
response = gl.nondet.web.get(self.resolution_url)
web_data = response.body.decode("utf-8")
Comment on lines +52 to +53
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In the current GenLayer Python API/docs, what does gl.nondet.web.get() return, and which API is recommended when an LLM prompt needs rendered or plain-text webpage content instead of raw HTML bytes?

💡 Result:

  • gl.nondet.web.get(url, *, headers={}) returns a gl.nondet.web.Response object with fields:

    • status: int
    • headers: dict[str, bytes]
    • body: bytes | None (i.e., the response payload is raw bytes, not a decoded string) [1]
  • If you need webpage content suitable for an LLM prompt (rendered page + plain text or HTML string), the recommended API is gl.nondet.web.render() (browser-like rendering), using:

    • mode='text' for plain-text content, or
    • mode='html' for rendered HTML as a str [1]
      (As opposed to gl.nondet.web.get(), which gives you raw bytes in Response.body.) [1]

Sources: [1]


Use gl.nondet.web.render() for LLM-suitable webpage content.

Lines 52-53 use gl.nondet.web.get(), which returns raw HTTP body bytes. For an LLM extraction prompt, use gl.nondet.web.render(mode='text') instead to feed plain-text rendered content rather than raw HTML noise:

Suggested change:
response = gl.nondet.web.render(self.resolution_url, mode='text')
web_data = response
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/developers/intelligent-contracts/examples/prediction.mdx` around lines
52 - 53, Replace the raw HTTP fetch with the LLM-friendly renderer: instead of
calling gl.nondet.web.get(self.resolution_url) and decoding bytes into web_data,
call gl.nondet.web.render(self.resolution_url, mode='text') and assign its
returned text directly to web_data so the prompt receives plain-text rendered
content; update any references to response to use web_data and remove the
.body.decode(...) flow.

print(web_data)

task = f"""In the following web page, find the winning team in a matchup between the following teams:
Expand All @@ -73,11 +74,11 @@ class PredictionMarket(gl.Contract):
your output must be only JSON without any formatting prefix or suffix.
This result should be perfectly parsable by a JSON parser without errors.
"""
result = gl.exec_prompt(task).replace("```json", "").replace("```", "")
result = gl.nondet.exec_prompt(task).replace("```json", "").replace("```", "")
print(result)
return json.dumps(json.loads(result), sort_keys=True)

result_json = json.loads(gl.eq_principle_strict_eq(nondet))
result_json = json.loads(gl.eq_principle.strict_eq(nondet))

if result_json["winner"] > -1:
self.has_resolved = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The Storage contract sets up a simple scenario to store and retrieve a string value. This contract demonstrates basic data storage and retrieval functionality within a blockchain environment.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
The UserStorage contract sets up a scenario to store and retrieve string values associated with different user accounts. This contract demonstrates basic per-user data storage and retrieval functionality within a blockchain environment.

```python
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }

from genlayer import *

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ The LogIndexer contract demonstrates how to use the Vector Store database (VecDB
```python
# {
# "Seq": [
# { "Depends": "py-lib-genlayermodelwrappers:test" },
# { "Depends": "py-genlayer:test" }
# { "Depends": "py-lib-genlayermodelwrappers:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" },
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
# ]
# }

Expand All @@ -17,6 +17,7 @@ from dataclasses import dataclass
import typing


@allow_storage
@dataclass
class StoreValue:
log_id: u256
Expand Down
Loading
Loading