diff --git a/.github/workflows/jac-gpt-release.yml b/.github/workflows/jac-gpt-release.yml
new file mode 100644
index 0000000..44bb657
--- /dev/null
+++ b/.github/workflows/jac-gpt-release.yml
@@ -0,0 +1,73 @@
+name: Release on Docs Sync
+
+on:
+ workflow_run:
+ workflows: ["Sync Jaseci Docs"]
+ types:
+ - completed
+ branches:
+ - jac-gpt_optimization
+
+jobs:
+ create-release:
+ runs-on: ubuntu-latest
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Get latest tag
+ id: get_tag
+ run: |
+ git fetch --tags
+ LATEST_TAG=$(git tag -l "jac-gpt-v*" | sort -V | tail -n 1)
+ if [ -z "$LATEST_TAG" ]; then
+ LATEST_TAG="jac-gpt-v0.0.0"
+ fi
+ echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
+ echo "Found latest tag: $LATEST_TAG"
+
+ - name: Bump version
+ id: bump_version
+ run: |
+ LATEST_TAG=${{ steps.get_tag.outputs.latest_tag }}
+ # Extract version number: jac-gpt-v0.6.8 -> 0.6.8
+ VERSION=${LATEST_TAG#jac-gpt-v}
+
+ IFS='.' read -ra PARTS <<< "$VERSION"
+ MAJOR=${PARTS[0]:-0}
+ MINOR=${PARTS[1]:-0}
+ PATCH=${PARTS[2]:-0}
+
+ # Always bump patch version
+ PATCH=$((PATCH + 1))
+
+ NEW_VERSION="jac-gpt-v$MAJOR.$MINOR.$PATCH"
+ echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
+ echo "Creating release: $NEW_VERSION (bumped patch from $LATEST_TAG)"
+
+ - name: Create Release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ steps.bump_version.outputs.new_version }}
+ release_name: Release ${{ steps.bump_version.outputs.new_version }}
+ body: |
+ ## JAC-GPT Release ${{ steps.bump_version.outputs.new_version }}
+
+ π Automated release triggered by documentation sync
+
+ ### Changes
+ - Updated documentation from Jaseci repository
+
+ ### Deployment
+ This release will automatically trigger Docker image builds and deployment to:
+ - **Backend API**: https://jac-gpt-api.jaseci.org
+ - **Frontend**: https://jac-gpt.jaseci.org
+ draft: false
+ prerelease: false
diff --git a/jac-gpt/.gitignore b/jac-gpt/.gitignore
index 656cc33..a496af3 100644
--- a/jac-gpt/.gitignore
+++ b/jac-gpt/.gitignore
@@ -3,4 +3,5 @@ server/mydatabase/
__pycache__/
*.bin
*.sqlite3
-*.pickle
\ No newline at end of file
+*.pickle
+!test_dataset.json
\ No newline at end of file
diff --git a/jac-gpt/server/docs/assets/examples/basic/assignments.jac b/jac-gpt/server/docs/assets/examples/basic/assignments.jac
index 5989244..400b9c8 100644
--- a/jac-gpt/server/docs/assets/examples/basic/assignments.jac
+++ b/jac-gpt/server/docs/assets/examples/basic/assignments.jac
@@ -1,6 +1,6 @@
with entry {
a = b=16;
- let c = 18;
+ c = 18;
print(a, b, c);
a >>= 2;
print(a);
diff --git a/jac-gpt/server/docs/communityhub/breaking_changes.md b/jac-gpt/server/docs/communityhub/breaking_changes.md
index 154fe8e..d19d6fd 100644
--- a/jac-gpt/server/docs/communityhub/breaking_changes.md
+++ b/jac-gpt/server/docs/communityhub/breaking_changes.md
@@ -6,6 +6,37 @@ This page documents significant breaking changes in Jac and Jaseci that may affe
MTLLM library is now deprecated and replaced by the byLLM package. In all place where `mtllm` was used before can be replaced with `byllm`.
+### Version 0.9.4
+
+#### 1. `let` Keyword Removed - Use Direct Assignment
+
+The `let` keyword has been removed from Jaclang. Variable declarations now use direct assignment syntax, aligning with Python's approach to variable binding.
+
+**Before**
+
+```jac
+with entry {
+ let x = 10;
+ let name = "Alice";
+ let [count, setCount] = useState(0);
+}
+```
+
+**After**
+
+```jac
+with entry {
+ x = 10;
+ name = "Alice";
+ [count, setCount] = useState(0);
+}
+```
+
+**Key Changes:**
+- Remove the `let` keyword from all variable declarations
+- Use direct assignment (`x = value`) instead of `let x = value`
+- This applies to all contexts including destructuring assignments
+
### Version 0.8.10
#### 1. byLLM Imports Moved to `byllm.lib`
diff --git a/jac-gpt/server/docs/communityhub/release_notes/jaclang.md b/jac-gpt/server/docs/communityhub/release_notes/jaclang.md
index 39a29b7..7debf7b 100644
--- a/jac-gpt/server/docs/communityhub/release_notes/jaclang.md
+++ b/jac-gpt/server/docs/communityhub/release_notes/jaclang.md
@@ -4,8 +4,10 @@ This document provides a summary of new features, improvements, and bug fixes in
## jaclang 0.9.4 (Unreleased)
+- **`let` Keyword Removed**: The `let` keyword has been removed from Jaclang. Variable declarations now use direct assignment syntax (e.g., `x = 10` instead of `let x = 10`), aligning with Python's approach to variable binding.
+- **Py2Jac Robustness Improvements**: Improved reliability of Python-to-Jac conversion with better handling of f-strings (smart quote switching, no keyword escaping in interpolations), match pattern class names, attribute access formatting (no extra spaces around dots), and nested docstrings in classes and functions.
- **Format Command Enhancements**: The `jac format` command now tracks and reports which files were actually changed during formatting. The summary output shows both total files processed and the count of files that were modified (e.g., `Formatted 10/12 '.jac' files (3 changed).`). Additionally, syntax errors encountered during formatting are now printed with full error details.
-- **Py2Jac Stability**: Fixed conversion of Python code with augmented assignments and nested docstrings so generated Jac no longer redeclares targets or merges docstrings into following defs.
+- **F-String Escape Sequence Fix**: Fixed a bug where escape sequences like `\n`, `\t`, etc. inside f-strings were not being properly decoded, causing literal backslash-n to appear in output instead of actual newlines. The fix correctly decodes escape sequences for f-string literal fragments in `unitree.py`.
## jaclang 0.9.3 (Latest Release)
diff --git a/jac-gpt/server/docs/learn/imports/basics.md b/jac-gpt/server/docs/learn/imports/basics.md
new file mode 100644
index 0000000..f50bf60
--- /dev/null
+++ b/jac-gpt/server/docs/learn/imports/basics.md
@@ -0,0 +1,182 @@
+# Import Basics
+
+Jac provides a powerful and flexible import system to organize code across multiple files and packages.
+
+!!! tip "Prefer Absolute Imports"
+ **We recommend using absolute imports** over relative imports. Absolute imports are explicit, easier to read, and avoid ambiguity.
+
+---
+
+## Import Syntax Overview
+
+| Pattern | Syntax | Use Case |
+|---------|--------|----------|
+| Absolute import | `import module;` | Import entire module |
+| From-import | `import from module { X, Y }` | Import specific symbols |
+| Include (wildcard) | `include module;` | Include all symbols into namespace |
+| Aliased import | `import module as alias;` | Rename module |
+| From-import alias | `import from module { X as Y }` | Rename symbol |
+
+!!! note "File Extensions"
+ Jac resolves both `.jac` and `.py` filesβyou don't need to include the extension in import paths. This makes Jac fully interoperable with Python modules.
+
+---
+
+## Absolute Import
+
+Import an entire module and access its members using dot notation.
+
+> π [**absolute_import/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/absolute_import)
+
+=== "main.jac"
+ ```jac title="absolute_import/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/absolute_import/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/absolute_import/main.jac)
+
+=== "module_a.jac"
+ ```jac title="absolute_import/module_a.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/absolute_import/module_a.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/absolute_import/module_a.jac)
+
+```
+absolute_import/
+βββ main.jac
+βββ module_a.jac
+```
+
+??? example "Output"
+ ```
+ Absolute import - VALUE_A: Hello from module_a
+ Absolute import - greet(): Greet from module_a
+ ```
+
+!!! tip "When to use"
+ Use absolute imports when you need multiple items from a module and want to make the source clear (e.g., `module_a.VALUE_A`).
+
+---
+
+## From-Import (Selective Import)
+
+Import specific symbols directly into your namespace.
+
+> π [**from_import/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/from_import)
+
+=== "main.jac"
+ ```jac title="from_import/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/from_import/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/from_import/main.jac)
+
+=== "module_b.jac"
+ ```jac title="from_import/module_b.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/from_import/module_b.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/from_import/module_b.jac)
+
+```
+from_import/
+βββ main.jac
+βββ module_b.jac
+```
+
+??? example "Output"
+ ```
+ From-import - VALUE_B: Hello from module_b
+ From-import - calculate(5): 10
+ From-import - MyClass: MyClass instance
+ ```
+
+!!! tip "When to use"
+ Use from-imports when you need specific items and want shorter names in your code.
+
+---
+
+## Include Statement (Wildcard Import)
+
+The `include` statement imports all public symbols from a module directly into your namespace.
+
+> π [**include_statement/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/include_statement)
+
+=== "main.jac"
+ ```jac title="include_statement/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/include_statement/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/include_statement/main.jac)
+
+=== "module_c.jac"
+ ```jac title="include_statement/module_c.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/include_statement/module_c.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/include_statement/module_c.jac)
+
+```
+include_statement/
+βββ main.jac
+βββ module_c.jac
+```
+
+??? example "Output"
+ ```
+ Star import - PUBLIC_VAR: I am public
+ Star import - public_func(): Public function
+ ```
+
+!!! info "Private symbols"
+ Symbols starting with `_` (underscore) are considered private and are **not** included.
+
+!!! warning "Use sparingly"
+ Include statements can pollute your namespace. Prefer explicit imports in production code.
+
+---
+
+## Aliased Imports
+
+Rename modules or symbols during import to avoid conflicts or for convenience.
+
+> π [**aliased_import/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/aliased_import)
+
+=== "main.jac"
+ ```jac title="aliased_import/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/aliased_import/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/aliased_import/main.jac)
+
+=== "module_d.jac"
+ ```jac title="aliased_import/module_d.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/aliased_import/module_d.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/aliased_import/module_d.jac)
+
+```
+aliased_import/
+βββ main.jac
+βββ module_d.jac
+```
+
+??? example "Output"
+ ```
+ Import as - md.LONG_MODULE_VALUE: Value from long named module
+ From import as - lfn(): Result from long function
+ ```
+
+!!! tip "When to use"
+ - Shorten long module names
+ - Avoid naming conflicts
+ - Create more descriptive names
+
+---
+
+## Key Takeaways
+
+| Concept | Description |
+|---------|-------------|
+| **`import X;`** | Access via `X.symbol` |
+| **`import from X { Y }`** | Access `Y` directly |
+| **`include X;`** | All public symbols available directly |
+| **`import X as Z;`** | Access via `Z.symbol` |
+| **`import from X { Y as Z }`** | Access `Y` as `Z` |
+
+!!! success "Best Practice: Use Absolute Imports"
+ Absolute imports like `import from mypackage.module { X }` are clearer and more maintainable than relative imports.
diff --git a/jac-gpt/server/docs/learn/imports/packages.md b/jac-gpt/server/docs/learn/imports/packages.md
new file mode 100644
index 0000000..110e382
--- /dev/null
+++ b/jac-gpt/server/docs/learn/imports/packages.md
@@ -0,0 +1,273 @@
+# Packages
+
+Packages in Jac are directories containing `.jac` or `.py` files.
+
+!!! tip "Prefer Absolute Imports"
+ Use absolute imports like `import from mypackage.module { X }` for clarity and maintainability.
+
+---
+
+## Simple Package (No `__init__.jac` Required)
+
+Import directly from a package directory. The `__init__.jac` file is **optional**.
+
+> π [**package_no_init/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_no_init)
+
+=== "main.jac"
+ ```jac title="package_no_init/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/package_no_init/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_no_init/main.jac)
+
+=== "mylib/math_utils.jac"
+ ```jac title="package_no_init/mylib/math_utils.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/package_no_init/mylib/math_utils.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_no_init/mylib/math_utils.jac)
+
+=== "mylib/string_utils.jac"
+ ```jac title="package_no_init/mylib/string_utils.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/package_no_init/mylib/string_utils.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_no_init/mylib/string_utils.jac)
+
+```
+package_no_init/
+βββ main.jac
+βββ mylib/ # No __init__.jac needed!
+ βββ math_utils.jac
+ βββ string_utils.jac
+```
+
+??? example "Output"
+ ```
+ add(3, 5): 8
+ multiply(4, 6): 24
+ greet('World'): Hello, World!
+ ```
+
+---
+
+## Package with Re-exports
+
+Use `__init__.jac` when you want to create a simplified public API.
+
+> π [**package_basic/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_basic)
+
+=== "main.jac"
+ ```jac title="package_basic/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/package_basic/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_basic/main.jac)
+
+=== "mypackage/__init__.jac"
+ ```jac title="package_basic/mypackage/__init__.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/package_basic/mypackage/__init__.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_basic/mypackage/__init__.jac)
+
+=== "mypackage/helper.jac"
+ ```jac title="package_basic/mypackage/helper.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/package_basic/mypackage/helper.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/package_basic/mypackage/helper.jac)
+
+```
+package_basic/
+βββ main.jac
+βββ mypackage/
+ βββ __init__.jac # Re-exports from helper.jac
+ βββ helper.jac
+```
+
+??? example "Output"
+ ```
+ Package from-import - HELPER_VALUE: Helper value from package
+ Package from-import - helper_func(): Helper function result
+ ```
+
+---
+
+## Nested Package Imports
+
+Access deeply nested packages using dot notation.
+
+> π [**nested_packages/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages)
+
+=== "main.jac"
+ ```jac title="nested_packages/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/main.jac)
+
+=== "app/__init__.jac"
+ ```jac title="nested_packages/app/__init__.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/__init__.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/__init__.jac)
+
+=== "app/constants.jac"
+ ```jac title="nested_packages/app/constants.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/constants.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/constants.jac)
+
+=== "app/models/user.jac"
+ ```jac title="nested_packages/app/models/user.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/models/user.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/models/user.jac)
+
+=== "app/services/user_service.jac"
+ ```jac title="nested_packages/app/services/user_service.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/services/user_service.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/nested_packages/app/services/user_service.jac)
+
+```
+nested_packages/
+βββ main.jac
+βββ app/
+ βββ __init__.jac
+ βββ constants.jac
+ βββ models/
+ β βββ __init__.jac
+ β βββ user.jac
+ βββ services/
+ βββ __init__.jac
+ βββ user_service.jac
+```
+
+??? example "Output"
+ ```
+ Nested deep - APP_NAME: MyApp
+ Nested deep - get_version(): 1.0.0
+ Nested deep - create_user('Alice'): User(Alice) from MyApp
+ ```
+
+---
+
+## Re-exports with `__init__.jac`
+
+While optional, `__init__.jac` can be used to create a clean public API by re-exporting symbols.
+
+> π [**init_reexport/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport)
+
+=== "main.jac"
+ ```jac title="init_reexport/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/main.jac)
+
+=== "mathlib/__init__.jac"
+ ```jac title="init_reexport/mathlib/__init__.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/__init__.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/__init__.jac)
+
+=== "mathlib/operations.jac"
+ ```jac title="init_reexport/mathlib/operations.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/operations.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/operations.jac)
+
+=== "mathlib/constants.jac"
+ ```jac title="init_reexport/mathlib/constants.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/constants.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/constants.jac)
+
+=== "mathlib/calculator.jac"
+ ```jac title="init_reexport/mathlib/calculator.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/calculator.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/init_reexport/mathlib/calculator.jac)
+
+```
+init_reexport/
+βββ main.jac
+βββ mathlib/
+ βββ __init__.jac # Re-exports from submodules
+ βββ calculator.jac
+ βββ constants.jac
+ βββ operations.jac
+```
+
+??? example "Output"
+ ```
+ Init reexport - add(5, 3): 8
+ Init reexport - subtract(10, 4): 6
+ Init reexport - multiply(6, 7): 42
+ Init reexport - divide(20, 4): 5.0
+ Init reexport - PI: 3.14159
+ Init reexport - E: 2.71828
+ Init reexport - Calculator.compute(10, 2, 'add'): 12
+ ```
+
+!!! tip "When to use `__init__.jac`"
+ Use `__init__.jac` when you want to:
+
+ - Create a simplified public API
+ - Hide internal module structure
+ - Add package-level constants or initialization
+
+---
+
+## Sibling Subpackage Imports
+
+Import between sibling subpackages using absolute paths.
+
+> π [**sibling_subpackage/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/sibling_subpackage)
+
+=== "main.jac"
+ ```jac title="sibling_subpackage/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/sibling_subpackage/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/sibling_subpackage/main.jac)
+
+=== "top/sub_a/a_module.jac"
+ ```jac title="sibling_subpackage/top/sub_a/a_module.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/sibling_subpackage/top/sub_a/a_module.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/sibling_subpackage/top/sub_a/a_module.jac)
+
+=== "top/sub_b/b_module.jac"
+ ```jac title="sibling_subpackage/top/sub_b/b_module.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/sibling_subpackage/top/sub_b/b_module.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/sibling_subpackage/top/sub_b/b_module.jac)
+
+```
+sibling_subpackage/
+βββ main.jac
+βββ top/
+ βββ __init__.jac
+ βββ sub_a/
+ β βββ __init__.jac
+ β βββ a_module.jac
+ βββ sub_b/
+ βββ __init__.jac
+ βββ b_module.jac # Can import from sub_a
+```
+
+??? example "Output"
+ ```
+ Sibling subpkg - A_VALUE: A module value
+ Sibling subpkg - a_func(): A function
+ Sibling subpkg - B_VALUE: B uses A module value
+ Sibling subpkg - b_func(): B calls: A function
+ ```
+
+---
+
+## Key Takeaways
+
+| Concept | Description |
+|---------|-------------|
+| **Packages** | Directories with `.jac` or `.py` files |
+| **`__init__.jac`** | Optional, useful for re-exports |
+| **Absolute imports** | `import from pkg.subpkg.module { X }` |
+| **Nested access** | Use dot notation for deep packages |
+
+!!! success "Best Practice"
+ Use **absolute imports** with full package paths: `import from app.models.user { User }`. This is explicit and avoids ambiguity.
diff --git a/jac-gpt/server/docs/learn/imports/relative_imports.md b/jac-gpt/server/docs/learn/imports/relative_imports.md
new file mode 100644
index 0000000..458a59e
--- /dev/null
+++ b/jac-gpt/server/docs/learn/imports/relative_imports.md
@@ -0,0 +1,151 @@
+# Relative Imports
+
+Relative imports allow modules within a package to reference each other using `.` (current) and `..` (parent) notation.
+
+!!! warning "Prefer Absolute Imports"
+ **Relative imports can be ambiguous.** We recommend absolute imports in most cases. Use relative imports only for tightly coupled internal package code.
+
+---
+
+## Relative Import Syntax
+
+| Syntax | Meaning |
+|--------|---------|
+| `.module` | Same directory |
+| `..module` | Parent directory |
+| `...module` | Grandparent directory |
+
+---
+
+## Same-Level Imports (`.`)
+
+Import from modules in the same directory.
+
+> π [**relative_sibling/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_sibling)
+
+=== "main.jac"
+ ```jac title="relative_sibling/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_sibling/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_sibling/main.jac)
+
+=== "pkg/base.jac"
+ ```jac title="relative_sibling/pkg/base.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_sibling/pkg/base.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_sibling/pkg/base.jac)
+
+=== "pkg/sibling.jac"
+ ```jac title="relative_sibling/pkg/sibling.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_sibling/pkg/sibling.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_sibling/pkg/sibling.jac)
+
+```
+relative_sibling/
+βββ main.jac
+βββ pkg/
+ βββ base.jac # Defines BASE_VALUE, base_func
+ βββ sibling.jac # Uses .base to import
+```
+
+??? example "Output"
+ ```
+ Relative import - BASE_VALUE: Base value
+ Relative import - SIBLING_VALUE: Sibling uses Base value
+ Relative import - sibling_func(): Sibling calls: Base function
+ ```
+
+---
+
+## Parent-Level Imports (`..`)
+
+Import from the parent directory.
+
+> π [**relative_parent/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_parent)
+
+=== "main.jac"
+ ```jac title="relative_parent/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_parent/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_parent/main.jac)
+
+=== "project/config.jac"
+ ```jac title="relative_parent/project/config.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_parent/project/config.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_parent/project/config.jac)
+
+=== "project/sub/deep.jac"
+ ```jac title="relative_parent/project/sub/deep.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_parent/project/sub/deep.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/relative_parent/project/sub/deep.jac)
+
+```
+relative_parent/
+βββ main.jac
+βββ project/
+ βββ config.jac # Defines CONFIG_VALUE, DEBUG
+ βββ sub/
+ βββ deep.jac # Uses ..config to reach parent
+```
+
+??? example "Output"
+ ```
+ Parent relative - CONFIG_VALUE: Project config
+ Parent relative - DEEP_VALUE: Deep module using config: Project config
+ Parent relative - deep_func(): Deep function, DEBUG=True
+ ```
+
+---
+
+## Mixed Absolute and Relative
+
+You can combine both import styles, but prefer absolute imports for clarity.
+
+> π [**mixed_imports/**](https://github.com/Jaseci-Labs/jaseci/tree/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/mixed_imports)
+
+=== "main.jac"
+ ```jac title="mixed_imports/main.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/mixed_imports/main.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/mixed_imports/main.jac)
+
+=== "library/base.jac"
+ ```jac title="mixed_imports/library/base.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/mixed_imports/library/base.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/mixed_imports/library/base.jac)
+
+=== "library/extended.jac"
+ ```jac title="mixed_imports/library/extended.jac"
+ --8<-- "jac/jaclang/compiler/tests/fixtures/imports_fixture/mixed_imports/library/extended.jac"
+ ```
+ [π View on GitHub](https://github.com/Jaseci-Labs/jaseci/blob/main/jac/jaclang/compiler/tests/fixtures/imports_fixture/mixed_imports/library/extended.jac)
+
+```
+mixed_imports/
+βββ main.jac
+βββ library/
+ βββ base.jac
+ βββ extended.jac
+```
+
+??? example "Output"
+ ```
+ Mixed - BASE_ID (from import): 1000
+ Mixed - EXTENDED_ID: 1001
+ Mixed - get_extended_id(): Base: 1000, Extended: 1001
+ Mixed - lib_base.BASE_ID (alias): 1000
+ ```
+
+---
+
+---
+
+!!! warning "Relative Import Boundaries"
+ Relative imports only work within packages. You cannot use `..` to escape beyond your project's root.
+
+!!! success "Best Practice"
+ **Default to absolute imports.** They're explicit and don't break when you reorganize code.
diff --git a/jac-gpt/server/test_datasets/test_dataset.json b/jac-gpt/server/test_datasets/test_dataset.json
new file mode 100644
index 0000000..2b19113
--- /dev/null
+++ b/jac-gpt/server/test_datasets/test_dataset.json
@@ -0,0 +1,79 @@
+{
+ "test_cases": [
+ {
+ "id": "test_001",
+ "query": "How do I create a walker in Jac?",
+ "type": "coding"
+ },
+ {
+ "id": "test_002",
+ "query": "What is the difference between a walker and a node?",
+ "type": "QA"
+ },
+ {
+ "id": "test_003",
+ "query": "Show me an example of ability definition in Jac",
+ "type": "coding"
+ },
+ {
+ "id": "test_004",
+ "query": "What are the new features in the latest Jac release?",
+ "type": "QA"
+ },
+ {
+ "id": "test_005",
+ "query": "How does the by llm syntax work?",
+ "type": "coding"
+ },
+ {
+ "id": "test_006",
+ "query": "What is Jaseci?",
+ "type": "QA"
+ },
+ {
+ "id": "test_007",
+ "query": "Can you help me with Python?",
+ "type": "QA"
+ },
+ {
+ "id": "test_008",
+ "query": "What's the weather like today?",
+ "type": "QA"
+ },
+ {
+ "id": "test_009",
+ "query": "How do I use the visit keyword in Jac?",
+ "type": "coding"
+ },
+ {
+ "id": "test_010",
+ "query": "Explain the import syntax in Jac",
+ "type": "coding"
+ },
+ {
+ "id": "test_011",
+ "query": "What are the benefits of using Jac over Python?",
+ "type": "QA"
+ },
+ {
+ "id": "test_012",
+ "query": "How do I define an enum in Jac?",
+ "type": "coding"
+ },
+ {
+ "id": "test_013",
+ "query": "Tell me a joke",
+ "type": "QA"
+ },
+ {
+ "id": "test_014",
+ "query": "What is the purpose of the has keyword?",
+ "type": "QA"
+ },
+ {
+ "id": "test_015",
+ "query": "How do I install Jaseci?",
+ "type": "QA"
+ }
+ ]
+}
diff --git a/jac-gpt/server/test_evaluator.jac b/jac-gpt/server/test_evaluator.jac
new file mode 100644
index 0000000..d872a80
--- /dev/null
+++ b/jac-gpt/server/test_evaluator.jac
@@ -0,0 +1,238 @@
+import sys;
+import os;
+import json;
+import time;
+import from datetime {datetime}
+import from dotenv {load_dotenv}
+import from server {infer}
+
+
+"""Load test dataset from JSON file"""
+def load_test_dataset(file_path: str) -> dict {
+ try {
+ with open(file_path, "r", encoding="utf-8") as file {
+ data = json.load(file);
+ return data;
+ }
+ } except Exception as e {
+ print(f"Error loading test dataset: {e}");
+ return {"test_cases": []};
+ }
+}
+
+"""Save results to JSON file in logs folder"""
+def save_results(results: dict, output_dir: str = ".logs") -> str {
+ try {
+ # Create logs directory if it doesn't exist
+ os.makedirs(output_dir, exist_ok=True);
+
+ # Generate timestamp for filename
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S");
+ filename = f"eval_results_{timestamp}.json";
+ filepath = os.path.join(output_dir, filename);
+
+ # Save results
+ with open(filepath, "w", encoding="utf-8") as file {
+ json.dump(results, file, indent=2, ensure_ascii=False);
+ }
+
+ return filepath;
+ } except Exception as e {
+ print(f"Error saving results: {e}");
+ return "";
+ }
+}
+
+"""Calculate summary statistics from test results"""
+def calculate_summary(results: list[dict]) -> dict {
+ if not results {
+ return {
+ "total_tests": 0,
+ "min_latency_ms": 0.0,
+ "max_latency_ms": 0.0
+ };
+ }
+
+ successful = [r for r in results if r.get("success", False)];
+
+ total_latencies = [r["latency_ms"] for r in successful if "latency_ms" in r];
+
+ # Calculate min/max safely
+ min_lat = 0.0;
+ max_lat = 0.0;
+ if total_latencies {
+ min_lat = total_latencies[0];
+ max_lat = total_latencies[0];
+ for lat in total_latencies {
+ if lat < min_lat {
+ min_lat = lat;
+ }
+ if lat > max_lat {
+ max_lat = lat;
+ }
+ }
+ }
+
+ return {
+ "total_tests": len(results),
+ "min_latency_ms": min_lat,
+ "max_latency_ms": max_lat
+ };
+}
+
+"""Evaluate a test dataset and generate results with latency metrics"""
+def evaluate_test_dataset(
+ test_file: str = "test_dataset.json",
+ output_dir: str = ".logs",
+ verbose: bool = True,
+ notes: str = ""
+) {
+
+
+ print(f"\n{'='*60}");
+ print(f"Starting Test Evaluation");
+ print(f"{'='*60}");
+ print(f"Test file: {test_file}");
+ print(f"Output directory: {output_dir}\n");
+
+ # Load test dataset
+ dataset = load_test_dataset(test_file);
+ test_cases = dataset.get("test_cases", []);
+
+ if not test_cases {
+ print("No test cases found in dataset!");
+ return;
+ }
+
+ print(f"Loaded {len(test_cases)} test cases\n");
+
+ # Run tests
+ results = [];
+ for idx in range(len(test_cases)) {
+ test_case = test_cases[idx];
+ test_id = test_case.get("id", f"test_{idx+1}");
+ query = test_case.get("query", "");
+
+ if verbose {
+ print(f"\n[{idx+1}/{len(test_cases)}] Running: {test_id}");
+ print(f"Query: {query[:80]}{'...' if len(query) > 80 else ''}");
+ }
+
+ # Measure total latency
+ start_total = time.perf_counter();
+
+ try {
+ # Spawn infer walker from server.jac
+ response_walker = infer(message=query, chat_history=[]) spawn root;
+
+ end_total = time.perf_counter();
+ total_latency_ms = (end_total - start_total) * 1000;
+
+ # Extract response from walker
+ response = response_walker.response;
+
+ result = {
+ "test_id": test_id,
+ "query": query,
+ "response": response,
+ "response_length": len(response),
+ "latency_ms": round(total_latency_ms, 2),
+ "success": True,
+ "error": None
+ };
+
+ if verbose {
+ print(f"β Latency: {round(total_latency_ms, 2)}ms");
+ }
+
+ } except Exception as e {
+ end_total = time.perf_counter();
+ total_latency_ms = (end_total - start_total) * 1000;
+
+ result = {
+ "test_id": test_id,
+ "query": query,
+ "response": None,
+ "response_length": 0,
+ "latency_ms": round(total_latency_ms, 2),
+ "success": False,
+ "error": str(e)
+ };
+
+ if verbose {
+ print(f"β Error: {str(e)}");
+ }
+ }
+
+ results.append(result);
+ }
+
+ # Calculate summary
+ summary = calculate_summary(results);
+
+ # Prepare final output
+ output = {
+ "test_run_metadata": {
+ "timestamp": datetime.now().isoformat(),
+ "test_file": test_file,
+ "total_tests": len(test_cases),
+ "model": "gpt-4.1-mini",
+ "notes": notes if notes else "No notes provided"
+ },
+ "results": results,
+ "summary": summary
+ };
+
+ # Save to file
+ output_path = save_results(output, output_dir);
+
+ # Print summary
+ print(f"\n{'='*60}");
+ print(f"Evaluation Complete");
+ print(f"{'='*60}");
+ print(f"Total Tests: {summary['total_tests']}");
+ print(f"Min Latency: {summary['min_latency_ms']:.2f}ms");
+ print(f"Max Latency: {summary['max_latency_ms']:.2f}ms");
+ print(f"\nResults saved to: {output_path}");
+ print(f"{'='*60}\n");
+}
+
+with entry {
+ load_dotenv(override=True);
+
+ print("\n=== Test Evaluator ===");
+ print("1. Run test dataset");
+ print("2. Test custom query");
+ choice = input("Choose option (1 or 2): ").strip();
+
+ if choice == "1" {
+ notes = input("\nEnter notes for this test run (optional): ").strip();
+ test_file_path = "test_datasets/test_dataset.json";
+ evaluate_test_dataset(test_file=test_file_path, verbose=False, notes=notes);
+ } elif choice == "2" {
+ import from server {infer};
+ query = input("\nEnter your query: ").strip();
+
+ if query {
+ print(f"\nProcessing: {query}");
+ start = time.perf_counter();
+
+ response_walker = infer(message=query, chat_history=[]) spawn root;
+
+ end = time.perf_counter();
+ latency = (end - start) * 1000;
+
+ print(f"\n{'='*60}");
+ print(f"Response:");
+ print(f"{'='*60}");
+ print(response_walker.response);
+ print(f"\n{'='*60}");
+ print(f"Latency: {latency:.2f}ms");
+ print(f"{'='*60}\n");
+ } else {
+ print("No query provided.");
+ }
+ } else {
+ print("Invalid choice. Exiting.");
+ }
+}