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
34 changes: 17 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ jobs:
- name: Update version in __init__.py
run: |
VERSION="${{ steps.version.outputs.version }}"
sed -i "s/^__version__ = \".*\"/__version__ = \"$VERSION\"/" sentience/__init__.py
sed -i "s/^__version__ = \".*\"/__version__ = \"$VERSION\"/" predicate/__init__.py

- name: Verify extension files are present
run: |
echo "🔍 Verifying extension files are included..."

# Check required extension files exist
REQUIRED_FILES=(
"sentience/extension/manifest.json"
"sentience/extension/content.js"
"sentience/extension/background.js"
"sentience/extension/injected_api.js"
"sentience/extension/pkg/sentience_core.js"
"sentience/extension/pkg/sentience_core_bg.wasm"
"predicate/extension/manifest.json"
"predicate/extension/content.js"
"predicate/extension/background.js"
"predicate/extension/injected_api.js"
"predicate/extension/pkg/sentience_core.js"
"predicate/extension/pkg/sentience_core_bg.wasm"
)

MISSING_FILES=()
Expand All @@ -81,15 +81,15 @@ jobs:
fi

# Verify findTextRect function exists in injected_api.js
if ! grep -q "findTextRect:" sentience/extension/injected_api.js; then
if ! grep -q "findTextRect:" predicate/extension/injected_api.js; then
echo "❌ Error: findTextRect function not found in injected_api.js"
echo "The extension may be out of date. Please sync the extension before releasing."
exit 1
fi

echo "✅ All extension files verified"
echo "📦 Extension files that will be included:"
find sentience/extension -type f | sort
find predicate/extension -type f | sort

- name: Build package
run: |
Expand Down Expand Up @@ -117,10 +117,10 @@ jobs:

# Check for required extension files in the wheel
REQUIRED_IN_WHEEL=(
"sentience/extension/manifest.json"
"sentience/extension/injected_api.js"
"sentience/extension/pkg/sentience_core.js"
"sentience/extension/pkg/sentience_core_bg.wasm"
"predicate/extension/manifest.json"
"predicate/extension/injected_api.js"
"predicate/extension/pkg/sentience_core.js"
"predicate/extension/pkg/sentience_core_bg.wasm"
)

MISSING_IN_WHEEL=()
Expand All @@ -140,14 +140,14 @@ jobs:
fi

# Verify findTextRect is in the packaged injected_api.js
if ! grep -q "findTextRect:" sentience/extension/injected_api.js; then
if ! grep -q "findTextRect:" predicate/extension/injected_api.js; then
echo "❌ Error: findTextRect not found in packaged injected_api.js"
exit 1
fi

echo "✅ All extension files verified in built package"
echo "📦 Extension files found in wheel:"
find sentience/extension -type f | sort
find predicate/extension -type f | sort

# Cleanup
rm -rf "$TEMP_DIR"
Expand All @@ -166,11 +166,11 @@ jobs:
tag_name: v${{ steps.version.outputs.version }}
name: Release v${{ steps.version.outputs.version }}
body: |
Release v${{ steps.version.outputs.version }} of sentienceapi
Release v${{ steps.version.outputs.version }} of predicatelabs

## Installation
```bash
pip install sentienceapi==${{ steps.version.outputs.version }}
pip install predicatelabs==${{ steps.version.outputs.version }}
```
draft: false
prerelease: false
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/sync-extension.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: Sync Extension from sentience-chrome
name: Sync Extension from predicate-chrome

on:
repository_dispatch:
types: [extension-updated]
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag from sentience-chrome (e.g., v1.0.0)'
description: 'Release tag from predicate-chrome (e.g., v1.0.0)'
required: true
type: string
schedule:
Expand Down Expand Up @@ -147,7 +147,7 @@ jobs:
if: steps.release.outputs.skip != 'true'
run: |
# Target directory in sdk-python (inside the package source)
TARGET_DIR="sentience/extension"
TARGET_DIR="predicate/extension"

# Ensure target directory exists and is clean
rm -rf "$TARGET_DIR"
Expand All @@ -172,7 +172,7 @@ jobs:
if: steps.release.outputs.skip != 'true'
id: changes
run: |
git add sentience/extension/
git add predicate/extension/

if git diff --staged --quiet; then
echo "No changes detected."
Expand All @@ -196,10 +196,10 @@ jobs:
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.PR_TOKEN || secrets.GITHUB_TOKEN }}
commit-message: "chore: sync extension files from sentience-chrome ${{ steps.release.outputs.tag }}"
commit-message: "chore: sync extension files from predicate-chrome ${{ steps.release.outputs.tag }}"
title: "Sync Extension: ${{ steps.release.outputs.tag }}"
body: |
This PR syncs extension files from sentience-chrome release ${{ steps.release.outputs.tag }}.
This PR syncs extension files from predicate-chrome release ${{ steps.release.outputs.tag }}.

**Files updated:**
- Extension manifest and scripts
Expand Down
46 changes: 23 additions & 23 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ jobs:
shell: bash
run: |
pip cache purge || true
pip uninstall -y sentienceapi || true
pip uninstall -y predicatelabs || true
# Aggressively clean any bytecode cache (cross-platform Python approach)
python -c "import pathlib; [p.unlink() for p in pathlib.Path('.').rglob('*.pyc')]" || true
python -c "import pathlib, shutil; [shutil.rmtree(p) for p in pathlib.Path('.').rglob('__pycache__') if p.is_dir()]" || true
# Also clean .pyc files in sentience package specifically
find sentience -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || python -c "import pathlib, shutil; [shutil.rmtree(p) for p in pathlib.Path('sentience').rglob('__pycache__') if p.is_dir()]" || true
find sentience -name "*.pyc" -delete 2>/dev/null || python -c "import pathlib; [p.unlink() for p in pathlib.Path('sentience').rglob('*.pyc')]" || true
# Also clean .pyc files in predicate package specifically
find predicate -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || python -c "import pathlib, shutil; [shutil.rmtree(p) for p in pathlib.Path('predicate').rglob('__pycache__') if p.is_dir()]" || true
find predicate -name "*.pyc" -delete 2>/dev/null || python -c "import pathlib; [p.unlink() for p in pathlib.Path('predicate').rglob('*.pyc')]" || true
# Ensure source uses assert_ (no auto-rewrite).
python -c "import sys; import io; sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') if sys.platform == 'win32' else sys.stdout; content = open('sentience/agent_runtime.py', 'r', encoding='utf-8').read(); assert 'self.assertTrue(' not in content, 'Source file still has self.assertTrue('; print('OK: Source file verified: uses self.assert_()')"
python -c "import sys; import io; sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') if sys.platform == 'win32' else sys.stdout; content = open('predicate/agent_runtime.py', 'r', encoding='utf-8').read(); assert 'self.assertTrue(' not in content, 'Source file still has self.assertTrue('; print('OK: Source file verified: uses self.assert_()')"

# Force reinstall to ensure latest code
pip install --no-cache-dir --force-reinstall -e ".[dev]"
Expand All @@ -55,10 +55,10 @@ jobs:
git branch --show-current || echo "Detached HEAD"
echo ""
echo "=== Verify editable install (should point to local source) ==="
python -c "import sentience; import os; fpath = sentience.__file__; print(f'Package location: {fpath}'); print(f'Is in current dir: {os.path.abspath(fpath).startswith(os.getcwd())}'); print(f'Points to source: {os.path.exists(fpath)}')"
python -c "import predicate; import os; fpath = predicate.__file__; print(f'Package location: {fpath}'); print(f'Is in current dir: {os.path.abspath(fpath).startswith(os.getcwd())}'); print(f'Points to source: {os.path.exists(fpath)}')"
echo ""
echo "=== Source file line 345 (from repo) ==="
sed -n '345p' sentience/agent_runtime.py || python -c "with open('sentience/agent_runtime.py', 'r') as f: lines = f.readlines(); print(lines[344] if len(lines) > 344 else 'NOT FOUND')"
sed -n '345p' predicate/agent_runtime.py || python -c "with open('predicate/agent_runtime.py', 'r') as f: lines = f.readlines(); print(lines[344] if len(lines) > 344 else 'NOT FOUND')"
echo ""
echo "=== Installed package assert_done (from imported module) ==="
python << 'PYEOF'
Expand All @@ -72,11 +72,11 @@ jobs:
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')

from sentience.agent_runtime import AgentRuntime
from predicate.agent_runtime import AgentRuntime

# Verify it's using local source
import sentience
pkg_path = os.path.abspath(sentience.__file__)
import predicate
pkg_path = os.path.abspath(predicate.__file__)
cwd = os.getcwd()
if not pkg_path.startswith(cwd):
print(f'WARNING: Package is not from local source!')
Expand Down Expand Up @@ -120,13 +120,13 @@ jobs:

# Check agent_runtime.py line 345
print("=== Checking agent_runtime.py line 345 ===")
with open('sentience/agent_runtime.py', 'r', encoding='utf-8') as f:
with open('predicate/agent_runtime.py', 'r', encoding='utf-8') as f:
lines = f.readlines()
print(''.join(lines[339:350]))

# Verify assert_ method exists
print("\n=== Verifying assert_ method exists ===")
with open('sentience/agent_runtime.py', 'r', encoding='utf-8') as f:
with open('predicate/agent_runtime.py', 'r', encoding='utf-8') as f:
lines = f.readlines()
for i, line in enumerate(lines, 1):
if 'def assert_' in line:
Expand All @@ -135,7 +135,7 @@ jobs:
# Check for problematic assertTrue patterns (should NOT exist)
print("\n=== Checking for assertTrue patterns (should NOT exist) ===")
import re
with open('sentience/agent_runtime.py', 'r', encoding='utf-8') as f:
with open('predicate/agent_runtime.py', 'r', encoding='utf-8') as f:
content = f.read()
# Check for self.assertTrue( - this is the bug
if re.search(r'self\.assertTrue\s*\(', content):
Expand All @@ -156,14 +156,14 @@ jobs:
- name: Type check with mypy
continue-on-error: true
run: |
mypy sentience --ignore-missing-imports --no-strict-optional
mypy predicate --ignore-missing-imports --no-strict-optional

- name: Check code style
continue-on-error: true
run: |
black --check sentience tests --line-length=100
isort --check-only --profile black sentience tests
flake8 sentience tests --max-line-length=100 --extend-ignore=E203,W503,E501 --max-complexity=15
black --check predicate tests --line-length=100
isort --check-only --profile black predicate tests
flake8 predicate tests --max-line-length=100 --extend-ignore=E203,W503,E501 --max-complexity=15

- name: Build extension (if needed)
if: runner.os != 'Windows'
Expand Down Expand Up @@ -192,7 +192,7 @@ jobs:
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')

# Check the source file directly (not the installed package)
file_path = 'sentience/agent_runtime.py'
file_path = 'predicate/agent_runtime.py'
if not os.path.exists(file_path):
print(f'WARNING: {file_path} not found!')
sys.exit(0) # Don't fail if file doesn't exist
Expand Down Expand Up @@ -248,7 +248,7 @@ jobs:
print("=== Final Pre-Test Verification ===")

# First, verify the source file directly
source_file = 'sentience/agent_runtime.py'
source_file = 'predicate/agent_runtime.py'
print(f"=== Checking source file: {source_file} ===")
if not os.path.exists(source_file):
print(f"ERROR: Source file {source_file} not found!")
Expand Down Expand Up @@ -282,11 +282,11 @@ jobs:

# Now check the installed package
print("\n=== Checking installed package ===")
import sentience.agent_runtime
import predicate.agent_runtime

# Verify it's using local source (editable install)
import sentience
pkg_path = os.path.abspath(sentience.__file__)
import predicate
pkg_path = os.path.abspath(predicate.__file__)
cwd = os.getcwd()
if not pkg_path.startswith(cwd):
print(f'WARNING: Package is not from local source!')
Expand All @@ -296,7 +296,7 @@ jobs:
else:
print(f'OK: Package is from local source: {pkg_path}')

src = inspect.getsource(sentience.agent_runtime.AgentRuntime.assert_done)
src = inspect.getsource(predicate.agent_runtime.AgentRuntime.assert_done)

print("assert_done method source:")
print(src)
Expand Down
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ Thumbs.db
extension-temp/
playground/

# Allow bundled extension assets under sentience/extension/dist
!sentience/extension/dist/
!sentience/extension/dist/**
# Allow bundled extension assets under predicate/extension/dist
!predicate/extension/dist/
!predicate/extension/dist/**
22 changes: 11 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

#### Agent Tracing & Debugging
- **New Module: `sentience.tracing`** - Built-in tracing infrastructure for debugging and analyzing agent behavior
- **New Module: `predicate.tracing`** - Built-in tracing infrastructure for debugging and analyzing agent behavior
- `Tracer` class for recording agent execution
- `TraceSink` abstract base class for custom trace storage
- `JsonlTraceSink` for saving traces to JSONL files
- `TraceEvent` dataclass for structured trace events
- Trace events: `step_start`, `snapshot`, `llm_query`, `action`, `step_end`, `error`
- **New Module: `sentience.agent_config`** - Centralized agent configuration
- **New Module: `predicate.agent_config`** - Centralized agent configuration
- `AgentConfig` dataclass with defaults for snapshot limits, LLM settings, screenshot options
- **New Module: `sentience.utils`** - Snapshot digest utilities
- **New Module: `predicate.utils`** - Snapshot digest utilities
- `compute_snapshot_digests()` - Generate SHA256 fingerprints for loop detection
- `canonical_snapshot_strict()` - Digest including element text
- `canonical_snapshot_loose()` - Digest excluding text (layout only)
- `sha256_digest()` - Hash computation helper
- **New Module: `sentience.formatting`** - LLM prompt formatting
- **New Module: `predicate.formatting`** - LLM prompt formatting
- `format_snapshot_for_llm()` - Convert snapshots to LLM-friendly text format
- **Schema File: `sentience/schemas/trace_v1.json`** - JSON Schema for trace events, bundled with package
- **Schema File: `predicate/schemas/trace_v1.json`** - JSON Schema for trace events, bundled with package

#### Enhanced SentienceAgent
- Added optional `tracer` parameter to `SentienceAgent.__init__()` for execution tracking
Expand All @@ -40,8 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed
- Fixed linting errors across multiple files:
- `sentience/cli.py` - Removed unused variable `code` (F841)
- `sentience/inspector.py` - Removed unused imports (F401)
- `predicate/cli.py` - Removed unused variable `code` (F841)
- `predicate/inspector.py` - Removed unused imports (F401)
- `tests/test_inspector.py` - Removed unused `pytest` import (F401)
- `tests/test_recorder.py` - Removed unused imports (F401)
- `tests/test_smart_selector.py` - Removed unused `pytest` import (F401)
Expand Down Expand Up @@ -87,21 +87,21 @@ agent.act("Click the button") # Now traced!

```python
# Tracing
from sentience.tracing import Tracer, JsonlTraceSink, TraceEvent, TraceSink
from predicate.tracing import Tracer, JsonlTraceSink, TraceEvent, TraceSink

# Configuration
from sentience.agent_config import AgentConfig
from predicate.agent_config import AgentConfig

# Utilities
from sentience.utils import (
from predicate.utils import (
compute_snapshot_digests,
canonical_snapshot_strict,
canonical_snapshot_loose,
sha256_digest
)

# Formatting
from sentience.formatting import format_snapshot_for_llm
from predicate.formatting import format_snapshot_for_llm
```

### Notes
Expand Down
4 changes: 2 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
include sentience/schemas/*.json
recursive-include sentience/extension *.js *.json *.wasm *.d.ts
include predicate/schemas/*.json
recursive-include predicate/extension *.js *.json *.wasm *.d.ts
Loading
Loading