Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Deploy Docs to GitHub Pages

on:
push:
branches: [main]
branches: [feat/0.4.0]
workflow_dispatch:

permissions:
Expand Down
278 changes: 278 additions & 0 deletions .github/workflows/generate-from-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
name: Generate Node SDK from Python

on:
repository_dispatch:
types: [python-updated]

# Manual trigger for testing
workflow_dispatch:
inputs:
before_sha:
description: 'Before commit SHA in Python SDK'
required: false
after_sha:
description: 'After commit SHA in Python SDK'
required: false

jobs:
generate:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- name: Checkout Node SDK
uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Set commit SHAs
id: shas
run: |
if [[ "${{ github.event_name }}" == "repository_dispatch" ]]; then
echo "before_sha=${{ github.event.client_payload.before_sha }}" >> $GITHUB_OUTPUT
echo "after_sha=${{ github.event.client_payload.after_sha }}" >> $GITHUB_OUTPUT
echo "source_repo=${{ github.event.client_payload.source_repo }}" >> $GITHUB_OUTPUT
echo "commit_message=${{ github.event.client_payload.commit_message }}" >> $GITHUB_OUTPUT
echo "changed_files=${{ github.event.client_payload.changed_files }}" >> $GITHUB_OUTPUT
else
# Manual trigger
SOURCE_REPO="${{ github.repository_owner }}/videodb-python"
echo "source_repo=$SOURCE_REPO" >> $GITHUB_OUTPUT
echo "commit_message=Manual trigger" >> $GITHUB_OUTPUT
echo "changed_files=" >> $GITHUB_OUTPUT

if [[ -n "${{ inputs.before_sha }}" ]]; then
echo "before_sha=${{ inputs.before_sha }}" >> $GITHUB_OUTPUT
else
echo "before_sha=" >> $GITHUB_OUTPUT
fi

if [[ -n "${{ inputs.after_sha }}" ]]; then
echo "after_sha=${{ inputs.after_sha }}" >> $GITHUB_OUTPUT
else
echo "after_sha=main" >> $GITHUB_OUTPUT
fi
fi

- name: Clone Python SDK
env:
GH_TOKEN: ${{ secrets.SDK_SYNC_PAT }}
run: |
SOURCE_REPO="${{ steps.shas.outputs.source_repo }}"
AFTER_SHA="${{ steps.shas.outputs.after_sha }}"

echo "Cloning Python SDK from $SOURCE_REPO at $AFTER_SHA"

# Clone the Python SDK into a subdirectory
git clone --depth 1 "https://x-access-token:${GH_TOKEN}@github.com/${SOURCE_REPO}.git" python-sdk

# Checkout the specific commit if provided
if [[ -n "$AFTER_SHA" && "$AFTER_SHA" != "main" ]]; then
cd python-sdk
git fetch --depth 1 origin "$AFTER_SHA"
git checkout "$AFTER_SHA"
cd ..
fi

# Remove .git directory - makes it READ-ONLY reference, impossible to push
rm -rf python-sdk/.git

echo "Python SDK cloned as read-only reference"
ls -la python-sdk/videodb/

- name: Fetch Python SDK diff
id: diff
env:
GH_TOKEN: ${{ secrets.SDK_SYNC_PAT }}
run: |
SOURCE_REPO="${{ steps.shas.outputs.source_repo }}"
BEFORE_SHA="${{ steps.shas.outputs.before_sha }}"
AFTER_SHA="${{ steps.shas.outputs.after_sha }}"

echo "Fetching diff from $SOURCE_REPO"
echo "Before: $BEFORE_SHA"
echo "After: $AFTER_SHA"

# Fetch the diff
if [[ -n "$BEFORE_SHA" ]]; then
gh api \
-H "Accept: application/vnd.github.v3.diff" \
"/repos/$SOURCE_REPO/compare/${BEFORE_SHA}...${AFTER_SHA}" \
> python.diff 2>/dev/null || echo "Could not fetch diff"
else
echo "No before SHA available"
touch python.diff
fi

echo "Diff size: $(wc -l < python.diff) lines"

- name: Run Codex
uses: openai/codex-action@v1
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
model: o4-mini
sandbox: workspace-write
prompt: |
You are updating the VideoDB Node SDK to match changes made to the Python SDK.

## Python SDK Available (READ-ONLY)

The complete Python SDK is available at `./python-sdk/videodb/` for you to read.
You have FULL ACCESS to read any Python file to understand the complete context.

⚠️ IMPORTANT: The `python-sdk/` directory is READ-ONLY for reference.
- DO NOT write, modify, or create any files in `python-sdk/`
- DO NOT attempt to commit or push changes to the Python SDK
- ONLY read from `python-sdk/` to understand the source code
- ONLY write to the Node SDK files in `src/`

## Git Diff of Python SDK Changes

The following diff shows what changed in the Python SDK:

```diff
$(cat python.diff)
```

## File Mapping: Python SDK → Node SDK

The Python SDK files map to Node SDK files as follows:

| Python File | Node File | Description |
|-------------|-----------|-------------|
| `videodb/client.py` | `src/core/connection.ts` | Main client/connection class |
| `videodb/collection.py` | `src/core/collection.ts` | Collection operations |
| `videodb/video.py` | `src/core/video.ts` | Video class and methods |
| `videodb/audio.py` | `src/core/audio.ts` | Audio class and methods |
| `videodb/image.py` | `src/core/image.ts` | Image class and methods |
| `videodb/scene.py` | `src/core/scene.ts` | Scene class |
| `videodb/shot.py` | `src/core/shot.ts` | Shot class |
| `videodb/timeline.py` | `src/core/timeline.ts` | Timeline class |
| `videodb/search.py` | `src/core/search/` | Search functionality |
| `videodb/_constants.py` | `src/constants.ts` | Constants and enums |
| `videodb/_utils/` | `src/utils/` | Utility functions |
| Type definitions | `src/types/` | TypeScript interfaces |

## Your Task

1. **Identify which Python files changed** in the diff above
2. **Read the FULL Python file** from `./python-sdk/videodb/` to understand:
- The complete context of the change
- What class/enum/function the change belongs to
- The surrounding code structure
3. **Find the corresponding Node SDK file** using the mapping table
4. **Read the Node SDK file** to understand current patterns
5. **Replicate the exact same changes** in the Node SDK file:
- If a new method was added in Python, add the equivalent method in Node
- If a constant was added, add it to the same location in constants.ts
- If a new class was added, create the corresponding TypeScript class
- If parameters were added/changed, update the Node version accordingly

IMPORTANT: Always read the full Python source file, not just the diff, to understand WHERE and HOW to add the code.

## Translation Rules

| Python | TypeScript |
|--------|------------|
| `str` | `string` |
| `int`, `float` | `number` |
| `bool` | `boolean` |
| `None` | `null` or `undefined` |
| `Optional[X]` | `X \| undefined` or `X?` |
| `List[X]` | `X[]` |
| `Dict[str, X]` | `Record<string, X>` |
| `def method(self, ...)` | `async method(...): Promise<...>` |
| `@dataclass class Foo` | `interface Foo { ... }` |
| `snake_case` | `camelCase` |
| `UPPER_SNAKE_CASE` | `UPPER_SNAKE_CASE` (keep same for constants) |

## Node SDK Patterns

- Methods that call the API should be `async` and return `Promise<T>`
- Use the existing `this.connection.post()` / `this.connection.get()` patterns
- Types go in `src/types/` directory
- Exports are managed in `src/index.ts`

## Important

- Do NOT modify `package.json`, `version.ts`, or version numbers
- Do NOT change existing exports unless adding new ones
- Do NOT refactor unrelated code
- ONLY implement what the diff indicates was added/changed
- Convert `snake_case` to `camelCase` for methods and variables
- Keep `UPPER_SNAKE_CASE` for constants

- name: Check for changes and create PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Save diff content for PR body before cleanup
DIFF_CONTENT=$(head -200 python.diff 2>/dev/null || echo "No diff available")

# Clean up temporary files - DO NOT commit these
rm -f python.diff
rm -rf python-sdk

# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Check if there are changes
if git diff --quiet && git diff --staged --quiet; then
echo "No changes generated by Codex"
exit 0
fi

# Create branch
BRANCH="auto/python-sync-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH"
git add -A

# Commit
COMMIT_MSG="${{ steps.shas.outputs.commit_message }}"
git commit -m "feat: sync with Python SDK

Source: ${{ steps.shas.outputs.source_repo }}@${{ steps.shas.outputs.after_sha }}
Original commit: ${COMMIT_MSG}

Generated by OpenAI Codex"

# Push
git push origin "$BRANCH"

# Create PR
gh pr create \
--title "feat: sync with Python SDK" \
--body "## Summary

Automated SDK update to match Python SDK changes.

**Source**: \`${{ steps.shas.outputs.source_repo }}\`
**Commit**: \`${{ steps.shas.outputs.after_sha }}\`
**Original message**: ${{ steps.shas.outputs.commit_message }}

## Changes

This PR was automatically generated by Codex based on the following Python SDK diff:

<details>
<summary>Python SDK Diff</summary>

\`\`\`diff
${DIFF_CONTENT}
\`\`\`

</details>

## Review Checklist

- [ ] TypeScript types are correct
- [ ] Async/await patterns match existing code
- [ ] camelCase naming convention followed
- [ ] No breaking changes introduced
- [ ] Tests pass locally

---
*Generated by [OpenAI Codex](https://github.com/openai/codex)*"
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export const ApiPath = {
scenes: 'scenes',
timeline: 'timeline',
frame: 'frame',
/** Test assets */
test_assets: 'test-assets',
} as const;

export const ResponseStatus = {
Expand Down
16 changes: 16 additions & 0 deletions src/core/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,22 @@ export class Collection implements ICollection {
});
};

/**
* Delete the test asset.
* @param testAssetId - ID of the test asset to delete
* @returns A promise that resolves when delete is successful
* @throws an error if the request fails
*/
public deleteTestAsset = async (testAssetId: string) => {
if (!testAssetId.trim()) {
throw new VideodbError('Test asset ID cannot be empty');
}
return await this.#vhttp.delete<Record<string, never>>(
[ApiPath.test_assets, testAssetId],
{ params: { collection_id: this.meta.id } }
);
};

/**
* @param filePath - absolute path to a file
* @param callbackUrl- [optional] A url that will be called once upload is finished
Expand Down