diff --git a/.github/workflows/jules-remove-pr.yml b/.github/workflows/jules-remove-pr.yml new file mode 100644 index 0000000..3a295d4 --- /dev/null +++ b/.github/workflows/jules-remove-pr.yml @@ -0,0 +1,54 @@ +# Copyright NGGT.LightKeeper and Di120078. All Rights Reserved. + +name: Jules - Remove PR + +on: + pull_request: + types: + - opened + +permissions: + pull-requests: write + +jobs: + close-jules-pr: + if: | + startsWith(github.event.pull_request.head.ref, 'jules-docs-dev-') || + startsWith(github.event.pull_request.head.ref, 'jules-patchnotes-dev-') + runs-on: ubuntu-latest + timeout-minutes: 2 + + steps: + - name: Close Jules automation pull request + uses: actions/github-script@v9 + with: + script: | + const pr = context.payload.pull_request; + const owner = context.repo.owner; + const repo = context.repo.repo; + const number = pr.number; + + if (pr.state !== "open") { + core.info(`PR #${number} is already ${pr.state}; nothing to do.`); + return; + } + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: [ + "This pull request was closed automatically by CI.", + "", + "Head branch `jules-docs-dev-*` / `jules-patchnotes-dev-*` is merged by the Jules automation pipeline; an open PR is not required.", + ].join("\n"), + }); + + await github.rest.pulls.update({ + owner, + repo, + pull_number: number, + state: "closed", + }); + + core.info(`Closed PR #${number} (head: ${pr.head.ref}).`); diff --git a/.github/workflows/jules-update-docs.yml b/.github/workflows/jules-update-docs.yml new file mode 100644 index 0000000..0854521 --- /dev/null +++ b/.github/workflows/jules-update-docs.yml @@ -0,0 +1,99 @@ +# Copyright NGGT.LightKeeper and Di120078. All Rights Reserved. + +name: Jules - Update Docs + +on: + push: + branches-ignore: + - 'main' + - 'jules-docs-dev-*' + - 'jules-patchnotes-dev-*' + +jobs: + run-jules: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + permissions: + contents: write + issues: write + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + fetch-depth: 2 + + - name: Jules - Generate Prompt + id: generate-prompt + run: | + COMMIT_MESSAGE=$(git log -1 --pretty=%s HEAD) + CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD) + COMMIT_DIFF=$(git diff HEAD~1 HEAD) + # Cap oversized inputs so the request stays within Jules API and shell limits. + CHANGED_FILES=$(printf '%s' "${CHANGED_FILES:0:16384}") + COMMIT_DIFF=$(printf '%s' "${COMMIT_DIFF:0:524288}" | iconv -f UTF-8 -t UTF-8 -c) + + PROMPT="The task is created automatically by the CI/CD pipeline system. You are working in the ASLM Code repository. The project contains documentation in the 'Docs/ASLM/' directory based on the Hugo Framework (Lotus Docs theme). Reference pages are under Docs/ASLM/content/docs/ASLM-Code/ and must mirror source paths — preserve directory structure, only change the extension (for example API/mcp.py -> Docs/ASLM/content/docs/ASLM-Code/API/mcp.md; Apps/UI/static/js/main/chat-controller.js -> Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/chat-controller.md). Your task is to analyze the commit '${COMMIT_MESSAGE}' and add or update documentation for changed .py and .js files. Never create __init__.md (ignore __init__.py). Study existing documentation before writing and match its style. Do not change any files outside Docs/. Do not touch Docs/ASLM/content/docs/PatchNotes/. If there are no relevant .py/.js changes, make a commit without file changes. Name the output branch jules-docs-dev-BRANCH_NAME where BRANCH_NAME is a short descriptive name; always keep the jules-docs-dev- prefix (example: jules-docs-dev-mcp-update). If there were no relevant changes, use jules-docs-dev-YYYYMMDDHHmm (UTC). This task was created automatically and may have errors; follow the instructions as closely as possible. Modified files: '${CHANGED_FILES}'. Commit diff: '${COMMIT_DIFF}'." + + PROMPT_FILE="${RUNNER_TEMP}/jules_prompt.txt" + printf '%s' "$PROMPT" > "$PROMPT_FILE" + echo "prompt_file=$PROMPT_FILE" >> "$GITHUB_OUTPUT" + + - name: Jules - Create Session + id: create-session + env: + PROMPT_FILE: ${{ steps.generate-prompt.outputs.prompt_file }} + run: | + JSON_PAYLOAD=$(jq -n \ + --rawfile prompt "$PROMPT_FILE" \ + --arg source_repo "sources/github/${{ github.repository }}" \ + --arg branch "${{ github.ref_name }}" \ + --arg title "CI/CD: Update Docs for commit ${{ github.sha }}" \ + '{ + prompt: $prompt, + sourceContext: { + source: $source_repo, + githubRepoContext: { startingBranch: $branch } + }, + title: $title, + automationMode: "AUTO_CREATE_PR" + }') + + RESPONSE_JSON=$(curl -s -X POST \ + 'https://jules.googleapis.com/v1alpha/sessions' \ + -H "Content-Type: application/json" \ + -H 'X-Goog-Api-Key: ${{ secrets.JULES_API_KEY }}' \ + -d "$JSON_PAYLOAD") + + SESSION_NAME=$(echo "$RESPONSE_JSON" | jq -r '.name') + echo "Jules session started: $SESSION_NAME" + echo "session_name=$SESSION_NAME" >> $GITHUB_OUTPUT + { + echo 'api_response<> "$GITHUB_OUTPUT" + + - name: Jules - Report Result + if: always() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SESSION_NAME: ${{ steps.create-session.outputs.session_name }} + API_RESPONSE: ${{ steps.create-session.outputs.api_response }} + run: | + COMMIT_SHA="${{ github.event.after }}" + + if [[ -z "$SESSION_NAME" || "$SESSION_NAME" == "null" ]]; then + ERROR=$(echo "$API_RESPONSE" | jq -r '.error.message // "Unknown error"') + COMMENT_BODY="❌ Jules Docs: failed to create session. Error: ${ERROR}" + gh api --method POST -H "Accept: application/vnd.github+json" \ + "/repos/${{ github.repository }}/commits/$COMMIT_SHA/comments" \ + -f body="$COMMENT_BODY" + exit 1 + fi + + SESSION_URL="https://jules.google.com/session/$(basename $SESSION_NAME)" + COMMENT_BODY="🚀 Jules Docs session started. Jules will update documentation and open a PR into a \`jules-docs-dev-*\` branch. Track progress: ${SESSION_URL}" + echo "Posting comment: $COMMENT_BODY" + gh api --method POST -H "Accept: application/vnd.github+json" \ + "/repos/${{ github.repository }}/commits/$COMMIT_SHA/comments" \ + -f body="$COMMENT_BODY" diff --git a/.github/workflows/jules-update-patchnotes.yml b/.github/workflows/jules-update-patchnotes.yml new file mode 100644 index 0000000..caee1b5 --- /dev/null +++ b/.github/workflows/jules-update-patchnotes.yml @@ -0,0 +1,103 @@ +# Copyright NGGT.LightKeeper and Di120078. All Rights Reserved. + +name: Jules - Update Patch Notes + +on: + push: + branches: + - 'jules-docs-dev-*' + +jobs: + run-jules: + runs-on: ubuntu-latest + permissions: + contents: write + issues: write + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + fetch-depth: 3 + + - name: Jules - Generate Prompt + id: generate-prompt + run: | + JULES_DOCS_COMMIT_MESSAGE=$(git log -1 --pretty=%s HEAD) + JULES_DOCS_CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD) + JULES_DOCS_COMMIT_DIFF=$(git diff HEAD~1 HEAD) + + BASE_COMMIT_MESSAGE=$(git log -1 --pretty=%s HEAD~1) + BASE_CHANGED_FILES=$(git diff --name-only HEAD~2 HEAD~1) + BASE_COMMIT_DIFF=$(git diff HEAD~2 HEAD~1) + + # Cap oversized inputs so the request stays within Jules API and shell limits. + JULES_DOCS_CHANGED_FILES=$(printf '%s' "${JULES_DOCS_CHANGED_FILES:0:16384}") + JULES_DOCS_COMMIT_DIFF=$(printf '%s' "${JULES_DOCS_COMMIT_DIFF:0:524288}" | iconv -f UTF-8 -t UTF-8 -c) + BASE_CHANGED_FILES=$(printf '%s' "${BASE_CHANGED_FILES:0:16384}") + BASE_COMMIT_DIFF=$(printf '%s' "${BASE_COMMIT_DIFF:0:524288}" | iconv -f UTF-8 -t UTF-8 -c) + + PROMPT="The task is created automatically by the CI/CD pipeline system. You are working in the ASLM Code repository. The project contains documentation in the 'Docs/ASLM/' directory based on the Hugo Framework (Lotus Docs theme). This pipeline runs after the Jules documentation pipeline updated docs on a jules-docs-dev-* branch. Your task is to create a Patch Note summarizing changes from the user commit '${BASE_COMMIT_MESSAGE}' and the documentation commit '${JULES_DOCS_COMMIT_MESSAGE}'. Study existing patch notes in Docs/ASLM/content/docs/PatchNotes/ and match their style. Create one new .md file there named YYYYMMDDHHmm-Short-Name.md (YYYYMMDDHHmm = current UTC time). Include Hugo front matter: title, date (RFC3339), draft: false, description. Include sections: ## New Features, ## Bug Fixes, ## API Changes, ## Known Issues. Do not change any files outside Docs/ASLM/content/docs/PatchNotes/. Name the output branch jules-patchnotes-dev-BRANCH_NAME; always keep the jules-patchnotes-dev- prefix (example: jules-patchnotes-dev-mcp-update). If there were no meaningful changes, use jules-patchnotes-dev-YYYYMMDDHHmm (UTC) and an empty commit. This task was created automatically and may have errors; follow the instructions as closely as possible. User commit modified files: '${BASE_CHANGED_FILES}'. User commit diff: '${BASE_COMMIT_DIFF}'. Documentation pipeline modified files: '${JULES_DOCS_CHANGED_FILES}'. Documentation pipeline diff: '${JULES_DOCS_COMMIT_DIFF}'." + + PROMPT_FILE="${RUNNER_TEMP}/jules_prompt.txt" + printf '%s' "$PROMPT" > "$PROMPT_FILE" + echo "prompt_file=$PROMPT_FILE" >> "$GITHUB_OUTPUT" + + - name: Jules - Create Session + id: create-session + env: + PROMPT_FILE: ${{ steps.generate-prompt.outputs.prompt_file }} + run: | + JSON_PAYLOAD=$(jq -n \ + --rawfile prompt "$PROMPT_FILE" \ + --arg source_repo "sources/github/${{ github.repository }}" \ + --arg branch "${{ github.ref_name }}" \ + --arg title "CI/CD: Update Patch Notes for ${{ github.ref_name }}" \ + '{ + prompt: $prompt, + sourceContext: { + source: $source_repo, + githubRepoContext: { startingBranch: $branch } + }, + title: $title, + automationMode: "AUTO_CREATE_PR" + }') + + RESPONSE_JSON=$(curl -s -X POST \ + 'https://jules.googleapis.com/v1alpha/sessions' \ + -H "Content-Type: application/json" \ + -H 'X-Goog-Api-Key: ${{ secrets.JULES_API_KEY }}' \ + -d "$JSON_PAYLOAD") + + SESSION_NAME=$(echo "$RESPONSE_JSON" | jq -r '.name') + echo "Jules session started: $SESSION_NAME" + echo "session_name=$SESSION_NAME" >> $GITHUB_OUTPUT + { + echo 'api_response<> "$GITHUB_OUTPUT" + + - name: Jules - Report Result + if: always() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SESSION_NAME: ${{ steps.create-session.outputs.session_name }} + API_RESPONSE: ${{ steps.create-session.outputs.api_response }} + run: | + COMMIT_SHA="${{ github.event.after }}" + + if [[ -z "$SESSION_NAME" || "$SESSION_NAME" == "null" ]]; then + ERROR=$(echo "$API_RESPONSE" | jq -r '.error.message // "Unknown error"') + COMMENT_BODY="❌ Jules Patch Notes: failed to create session. Error: ${ERROR}" + gh api --method POST -H "Accept: application/vnd.github+json" \ + "/repos/${{ github.repository }}/commits/$COMMIT_SHA/comments" \ + -f body="$COMMENT_BODY" + exit 1 + fi + + SESSION_URL="https://jules.google.com/session/$(basename $SESSION_NAME)" + COMMENT_BODY="🚀 Jules Patch Notes session started. Jules will create a patch note and open a PR into a \`jules-patchnotes-dev-*\` branch. Track progress: ${SESSION_URL}" + echo "Posting comment: $COMMENT_BODY" + gh api --method POST -H "Accept: application/vnd.github+json" \ + "/repos/${{ github.repository }}/commits/$COMMIT_SHA/comments" \ + -f body="$COMMENT_BODY" diff --git a/.github/workflows/pr-sync-docs.yml b/.github/workflows/pr-sync-docs.yml new file mode 100644 index 0000000..224ca7b --- /dev/null +++ b/.github/workflows/pr-sync-docs.yml @@ -0,0 +1,289 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +name: PR - Sync Docs + +on: + pull_request: + types: [opened, edited, synchronize] + +concurrency: + group: pr-sync-docs-${{ github.event.pull_request.number }} + cancel-in-progress: false + +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + # Scan: squash-merge Jules branches into PR head + scan: + if: | + github.actor != 'github-actions[bot]' && + !startsWith(github.event.pull_request.head.ref, 'jules-docs-dev-') && + !startsWith(github.event.pull_request.head.ref, 'jules-patchnotes-dev-') + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Find new Jules branches to merge + id: find-branches + uses: actions/github-script@v9 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const pr = context.payload.pull_request; + + async function isInPrHistory(sha) { + try { + const cmp = await github.rest.repos.compareCommitsWithBasehead({ + owner, repo, + basehead: `${sha}...${pr.head.sha}` + }); + return cmp.data.status !== 'behind' && cmp.data.status !== 'diverged'; + } catch (e) { + core.info(`Compare failed for ${sha}: ${e.message}`); + return false; + } + } + + async function countChangedFiles(base, head) { + const cmp = await github.rest.repos.compareCommitsWithBasehead({ + owner, repo, + basehead: `${base}...${head}` + }); + return (cmp.data.files || []).length; + } + + const comments = await github.paginate( + github.rest.issues.listComments, + { owner, repo, issue_number: pr.number } + ); + const alreadyTracked = new Set(); + const MARKER_RE = /([\s\S]*?)/g; + for (const c of comments) { + if (c.user.login !== 'github-actions[bot]') continue; + let m; + while ((m = MARKER_RE.exec(c.body)) !== null) { + m[1].trim().split('\n').forEach(l => { const b = l.trim(); if (b) alreadyTracked.add(b); }); + } + } + core.info(`Already tracked: ${[...alreadyTracked].join(', ') || '(none)'}`); + + const allBranches = await github.paginate( + github.rest.repos.listBranches, + { owner, repo, per_page: 100 } + ); + const docsBranches = allBranches + .map(b => b.name) + .filter(n => n.startsWith('jules-docs-dev-')); + const pnBranches = allBranches + .map(b => b.name) + .filter(n => n.startsWith('jules-patchnotes-dev-')); + + const toMerge = []; // { name, date } + const queued = new Set(); + const docsRefsToDelete = new Set(); // paired docs branches — delete after successful push + + function queueBranch(name, date) { + if (queued.has(name) || alreadyTracked.has(name)) return false; + toMerge.push({ name, date }); + queued.add(name); + return true; + } + + // ── 2. Scan via jules-docs-dev-* (primary path) ──────────────── + for (const docsBranch of docsBranches) { + if (alreadyTracked.has(docsBranch)) { + core.info(`Skip (already tracked): ${docsBranch}`); + continue; + } + + const docsCommits = await github.rest.repos.listCommits({ + owner, repo, sha: docsBranch, per_page: 100 + }); + if (docsCommits.data.length < 2) { + core.info(`Skip (< 2 commits): ${docsBranch}`); + continue; + } + + const anchorSHA = docsCommits.data[1].sha; + const lastDocsSHA = docsCommits.data[0].sha; + const anchorDate = new Date(docsCommits.data[1].commit.committer.date).getTime(); + + if (!(await isInPrHistory(anchorSHA))) { + core.info(`Skip (unrelated to this PR): ${docsBranch}`); + continue; + } + + let matchedPN = null; + for (const pnBranch of pnBranches) { + if (alreadyTracked.has(pnBranch) || queued.has(pnBranch)) continue; + const pnCommits = await github.rest.repos.listCommits({ + owner, repo, sha: pnBranch, per_page: 100 + }); + if (pnCommits.data.length < 2) continue; + if (pnCommits.data[1].sha === lastDocsSHA) { + matchedPN = pnBranch; + break; + } + } + + if (matchedPN) { + const changed = await countChangedFiles(lastDocsSHA, matchedPN); + if (changed === 0) { + core.info(`Skip empty patchnotes branch: ${matchedPN}`); + continue; + } + docsRefsToDelete.add(docsBranch); + core.info(`Queue patchnotes branch for merge: ${matchedPN}`); + queueBranch(matchedPN, anchorDate); + } else { + const changed = await countChangedFiles(anchorSHA, docsBranch); + if (changed === 0) { + core.info(`Skip empty docs branch: ${docsBranch}`); + continue; + } + core.info(`Queue docs branch for merge: ${docsBranch}`); + queueBranch(docsBranch, anchorDate); + } + } + + // ── 3. Orphan jules-patchnotes-dev-* (docs branch already gone) ─ + for (const pnBranch of pnBranches) { + if (queued.has(pnBranch) || alreadyTracked.has(pnBranch)) continue; + + const pnCommits = await github.rest.repos.listCommits({ + owner, repo, sha: pnBranch, per_page: 100 + }); + if (pnCommits.data.length < 2) { + core.info(`Skip orphan (< 2 commits): ${pnBranch}`); + continue; + } + + const docsCommitSha = pnCommits.data[1].sha; + let anchorSHA; + let anchorDate; + try { + const docsCommit = await github.rest.git.getCommit({ + owner, repo, commit_sha: docsCommitSha + }); + if (!docsCommit.data.parents?.length) { + core.info(`Skip orphan (no parent on docs commit): ${pnBranch}`); + continue; + } + anchorSHA = docsCommit.data.parents[0].sha; + const anchorCommit = await github.rest.git.getCommit({ + owner, repo, commit_sha: anchorSHA + }); + anchorDate = new Date(anchorCommit.data.committer.date).getTime(); + } catch (e) { + core.info(`Skip orphan (resolve anchor failed): ${pnBranch}: ${e.message}`); + continue; + } + + if (!(await isInPrHistory(anchorSHA))) { + core.info(`Skip orphan (unrelated to this PR): ${pnBranch}`); + continue; + } + + const changed = await countChangedFiles(docsCommitSha, pnBranch); + if (changed === 0) { + core.info(`Skip orphan empty patchnotes: ${pnBranch}`); + continue; + } + + core.info(`Queue orphan patchnotes branch for merge: ${pnBranch}`); + queueBranch(pnBranch, anchorDate); + } + + toMerge.sort((a, b) => a.date - b.date); + const toMergeNames = toMerge.map(e => e.name); + + core.info(`Branches to merge (sorted): ${toMergeNames.join(', ') || '(none)'}`); + core.setOutput('new_branches', JSON.stringify(toMergeNames)); + core.setOutput('docs_refs_to_delete', JSON.stringify([...docsRefsToDelete])); + + - name: Checkout PR head branch + if: steps.find-branches.outputs.new_branches != '[]' + uses: actions/checkout@v7 + with: + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Squash-merge Jules branches into PR head + if: steps.find-branches.outputs.new_branches != '[]' + env: + BRANCHES_JSON: ${{ steps.find-branches.outputs.new_branches }} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + for branch in $(echo "$BRANCHES_JSON" | jq -r '.[]'); do + git fetch origin "$branch" + if ! git merge --squash -X theirs "origin/$branch"; then + echo "::warning::Squash merge conflict for ${branch}; dropping this branch." + git merge --abort 2>/dev/null || true + git reset --hard HEAD + git clean -fd + continue + fi + if ! git diff --cached --quiet; then + git commit -m "chore: integrate Jules docs from ${branch} [skip ci]" + echo "Committed squash of ${branch}" + else + echo "Nothing to commit from ${branch} (already up-to-date)" + fi + done + + git push origin HEAD:${{ github.event.pull_request.head.ref }} + + - name: Post tracking comment + if: steps.find-branches.outputs.new_branches != '[]' + uses: actions/github-script@v9 + env: + BRANCHES_JSON: ${{ steps.find-branches.outputs.new_branches }} + with: + script: | + const branches = JSON.parse(process.env.BRANCHES_JSON); + const body = [ + '', + ...branches, + '' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body + }); + + - name: Delete merged Jules branches from remote + if: steps.find-branches.outputs.new_branches != '[]' + uses: actions/github-script@v9 + env: + BRANCHES_JSON: ${{ steps.find-branches.outputs.new_branches }} + DOCS_REFS_JSON: ${{ steps.find-branches.outputs.docs_refs_to_delete }} + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const merged = JSON.parse(process.env.BRANCHES_JSON); + const docsRefs = JSON.parse(process.env.DOCS_REFS_JSON || '[]'); + const toDelete = [...new Set([...merged, ...docsRefs])]; + + for (const branch of toDelete) { + try { + await github.rest.git.deleteRef({ owner, repo, ref: `heads/${branch}` }); + core.info(`Deleted remote branch after merge: ${branch}`); + } catch (e) { + if (e.status === 404 || e.status === 422) { + core.info(`Branch already gone: ${branch}`); + } else { + core.warning(`Could not delete ${branch}: ${e.message}`); + } + } + } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..52d511a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,362 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +name: Release + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + branches: + - main + push: + branches: + - main + +permissions: + contents: write + pull-requests: read + +concurrency: + group: release-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: false + +jobs: + stage-version: + if: > + github.event_name == 'pull_request' && + github.actor != 'github-actions[bot]' && + startsWith(github.event.pull_request.title, 'v') + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out PR head branch + uses: actions/checkout@v7 + with: + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Compute version + id: ver + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + set -uo pipefail + git fetch --tags --force origin + ENDPOINT=HEAD + # ── shared version computation (keep identical with the release job) ── + TITLE="$PR_TITLE" + if [[ ! "$TITLE" =~ ^v([0-9]+)\.([0-9]+)(-rc)?$ ]]; then + echo "Title '$TITLE' is not a release title (expected vG.S or vG.S-rc); skipping." + echo "valid=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + GLOBAL="${BASH_REMATCH[1]}" + SUB="${BASH_REMATCH[2]}" + IS_RC=false + [[ -n "${BASH_REMATCH[3]:-}" ]] && IS_RC=true + + # Non-rc release tags: vX.Y.Z or vX.Y.Z.W (older tags omit W). + mapfile -t NONRC < <(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$') + + # Z = number of existing non-rc revisions for vGLOBAL.SUB.* + declare -A seen_rev=() + for t in "${NONRC[@]}"; do + [[ "$t" =~ ^v${GLOBAL}\.${SUB}\.([0-9]+)(\.[0-9]+)?$ ]] && seen_rev["${BASH_REMATCH[1]}"]=1 + done + Z="${#seen_rev[@]}" + + # STABLE_BASE = highest non-rc tag with (g,s,r) < (GLOBAL,SUB,Z). + # Drives W (commit count) for both final and rc releases. + NEW_KEY=$(printf '%05d%05d%05d' "$GLOBAL" "$SUB" "$Z") + STABLE_BASE=""; BEST="" + for t in "${NONRC[@]}"; do + [[ "$t" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)(\.[0-9]+)?$ ]] || continue + k=$(printf '%05d%05d%05d' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}") + if [[ "$k" < "$NEW_KEY" ]] && { [[ -z "$BEST" ]] || [[ "$k" > "$BEST" ]]; }; then + BEST="$k"; STABLE_BASE="$t" + fi + done + + # W = commits in STABLE_BASE..ENDPOINT (cumulative from the last stable). + if [[ -n "$STABLE_BASE" ]]; then + W=$(git rev-list --count "${STABLE_BASE}..${ENDPOINT}") + else + W=$(git rev-list --count "${ENDPOINT}") + fi + # Stage (ENDPOINT=HEAD) writes before making its own stamp commit, so + # bump W by 1 to match the tag the release job counts from history. + [[ "$ENDPOINT" == HEAD ]] && W=$((W + 1)) + + # N = next rc ordinal; LATEST_RC = newest existing rc of this revision (vG.S.Z). + N=0; LATEST_RC="" + if $IS_RC; then + MAX_RC=0 + while read -r t; do + [[ "$t" =~ ^v${GLOBAL}\.${SUB}\.${Z}\.[0-9]+-rc([0-9]+)$ ]] || continue + if (( BASH_REMATCH[1] > MAX_RC )); then MAX_RC="${BASH_REMATCH[1]}"; LATEST_RC="$t"; fi + done < <(git tag --list "v${GLOBAL}.${SUB}.${Z}."'*-rc*') + N=$((MAX_RC + 1)) + fi + + # Changelog base: rc -> newest prior release of any kind; final -> last stable. + if $IS_RC && [[ -n "$LATEST_RC" ]]; then + CHANGELOG_BASE="$LATEST_RC" + else + CHANGELOG_BASE="$STABLE_BASE" + fi + + VERSION="${GLOBAL}.${SUB}.${Z}.${W}" + if $IS_RC; then TAG="v${VERSION}-rc${N}"; else TAG="v${VERSION}"; fi + ENDPOINT_SHA=$(git rev-parse "${ENDPOINT}") + { + echo "valid=true" + echo "version=${VERSION}" + echo "tag=${TAG}" + echo "is_rc=${IS_RC}" + echo "changelog_base=${CHANGELOG_BASE}" + echo "endpoint=${ENDPOINT_SHA}" + } >> "$GITHUB_OUTPUT" + echo "Computed TAG=${TAG} VERSION=${VERSION} STABLE_BASE=${STABLE_BASE:-} CHANGELOG_BASE=${CHANGELOG_BASE:-}" + # ── end shared version computation ────────────────────────────────── + + - name: Update ASLM_Module.json + if: steps.ver.outputs.valid == 'true' + env: + VERSION: ${{ steps.ver.outputs.version }} + TAG: ${{ steps.ver.outputs.tag }} + HEAD_REF: ${{ github.event.pull_request.head.ref }} + run: | + set -uo pipefail + # Surgical replace of the top-level "version" value (preserves formatting). + sed -i -E 's/^([[:space:]]*"version"[[:space:]]*:[[:space:]]*")[^"]*(".*)$/\1'"${VERSION}"'\2/' ASLM_Module.json + if git diff --quiet -- ASLM_Module.json; then + echo "ASLM_Module.json already at version ${VERSION}; nothing to commit." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add ASLM_Module.json + git commit -m "chore: set module version ${VERSION} for ${TAG} [skip ci]" + git push origin "HEAD:${HEAD_REF}" + + release: + if: github.event_name == 'push' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out main + uses: actions/checkout@v7 + with: + ref: main + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Resolve merged PR for this commit + id: pr + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -uo pipefail + SHA="${{ github.sha }}" + # PR number from the merge-commit subject is available immediately; + # the commits/{sha}/pulls index lags for several seconds after a merge. + SUBJECT=$(git show -s --format=%s "$SHA") + PR_NUMBER="" + if [[ "$SUBJECT" =~ ^Merge\ pull\ request\ #([0-9]+) ]]; then + PR_NUMBER="${BASH_REMATCH[1]}" + elif [[ "$SUBJECT" =~ \(#([0-9]+)\)$ ]]; then + PR_NUMBER="${BASH_REMATCH[1]}" + fi + # Fallback for non-standard subjects: ask which PR introduced the merged + # commit, retrying because that association can lag right after merge. + if [[ -z "$PR_NUMBER" ]]; then + LOOKUP=$(git rev-parse "${SHA}^2" 2>/dev/null || echo "$SHA") + for attempt in 1 2 3 4 5; do + PR_JSON=$(gh api -H "Accept: application/vnd.github+json" \ + "repos/${{ github.repository }}/commits/${LOOKUP}/pulls" 2>/dev/null || echo '[]') + PR_NUMBER=$(jq -r '[.[] | select(.base.ref == "main")] | last | .number // empty' <<<"$PR_JSON") + [[ -n "$PR_NUMBER" ]] && break + sleep 10 + done + fi + if [[ -z "$PR_NUMBER" ]]; then + echo "No PR found for ${SHA}; skipping." + echo "valid=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + PR=$(gh api -H "Accept: application/vnd.github+json" \ + "repos/${{ github.repository }}/pulls/${PR_NUMBER}" 2>/dev/null || echo '{}') + MERGED_AT=$(jq -r '.merged_at // empty' <<<"$PR") + BASE_REF=$(jq -r '.base.ref // empty' <<<"$PR") + if [[ -z "$MERGED_AT" || "$BASE_REF" != "main" ]]; then + echo "PR #${PR_NUMBER} not merged into main (base=${BASE_REF:-none}, merged_at=${MERGED_AT:-none}); skipping." + echo "valid=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "valid=true" >> "$GITHUB_OUTPUT" + echo "pr_title=$(jq -r '.title' <<<"$PR")" >> "$GITHUB_OUTPUT" + echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT" + echo "Resolved PR #${PR_NUMBER}: $(jq -r '.title' <<<"$PR")" + + - name: Compute version + if: steps.pr.outputs.valid == 'true' + id: ver + env: + PR_TITLE: ${{ steps.pr.outputs.pr_title }} + PR_NUMBER: ${{ steps.pr.outputs.pr_number }} + run: | + set -uo pipefail + git fetch --tags --force origin + # Use the PR head lineage as the endpoint so W/changelog match the + # value staged into ASLM_Module.json regardless of merge strategy. + git fetch origin "refs/pull/${PR_NUMBER}/head" + ENDPOINT=FETCH_HEAD + # ── shared version computation (keep identical with the stage job) ── + TITLE="$PR_TITLE" + if [[ ! "$TITLE" =~ ^v([0-9]+)\.([0-9]+)(-rc)?$ ]]; then + echo "Title '$TITLE' is not a release title (expected vG.S or vG.S-rc); skipping." + echo "valid=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + GLOBAL="${BASH_REMATCH[1]}" + SUB="${BASH_REMATCH[2]}" + IS_RC=false + [[ -n "${BASH_REMATCH[3]:-}" ]] && IS_RC=true + + # Non-rc release tags: vX.Y.Z or vX.Y.Z.W (older tags omit W). + mapfile -t NONRC < <(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$') + + # Z = number of existing non-rc revisions for vGLOBAL.SUB.* + declare -A seen_rev=() + for t in "${NONRC[@]}"; do + [[ "$t" =~ ^v${GLOBAL}\.${SUB}\.([0-9]+)(\.[0-9]+)?$ ]] && seen_rev["${BASH_REMATCH[1]}"]=1 + done + Z="${#seen_rev[@]}" + + # STABLE_BASE = highest non-rc tag with (g,s,r) < (GLOBAL,SUB,Z). + # Drives W (commit count) for both final and rc releases. + NEW_KEY=$(printf '%05d%05d%05d' "$GLOBAL" "$SUB" "$Z") + STABLE_BASE=""; BEST="" + for t in "${NONRC[@]}"; do + [[ "$t" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)(\.[0-9]+)?$ ]] || continue + k=$(printf '%05d%05d%05d' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}") + if [[ "$k" < "$NEW_KEY" ]] && { [[ -z "$BEST" ]] || [[ "$k" > "$BEST" ]]; }; then + BEST="$k"; STABLE_BASE="$t" + fi + done + + # W = commits in STABLE_BASE..ENDPOINT (cumulative from the last stable). + if [[ -n "$STABLE_BASE" ]]; then + W=$(git rev-list --count "${STABLE_BASE}..${ENDPOINT}") + else + W=$(git rev-list --count "${ENDPOINT}") + fi + # Stage (ENDPOINT=HEAD) writes before making its own stamp commit, so + # bump W by 1 to match the tag the release job counts from history. + [[ "$ENDPOINT" == HEAD ]] && W=$((W + 1)) + + # N = next rc ordinal; LATEST_RC = newest existing rc of this revision (vG.S.Z). + N=0; LATEST_RC="" + if $IS_RC; then + MAX_RC=0 + while read -r t; do + [[ "$t" =~ ^v${GLOBAL}\.${SUB}\.${Z}\.[0-9]+-rc([0-9]+)$ ]] || continue + if (( BASH_REMATCH[1] > MAX_RC )); then MAX_RC="${BASH_REMATCH[1]}"; LATEST_RC="$t"; fi + done < <(git tag --list "v${GLOBAL}.${SUB}.${Z}."'*-rc*') + N=$((MAX_RC + 1)) + fi + + # Changelog base: rc -> newest prior release of any kind; final -> last stable. + if $IS_RC && [[ -n "$LATEST_RC" ]]; then + CHANGELOG_BASE="$LATEST_RC" + else + CHANGELOG_BASE="$STABLE_BASE" + fi + + VERSION="${GLOBAL}.${SUB}.${Z}.${W}" + if $IS_RC; then TAG="v${VERSION}-rc${N}"; else TAG="v${VERSION}"; fi + ENDPOINT_SHA=$(git rev-parse "${ENDPOINT}") + { + echo "valid=true" + echo "version=${VERSION}" + echo "tag=${TAG}" + echo "is_rc=${IS_RC}" + echo "changelog_base=${CHANGELOG_BASE}" + echo "endpoint=${ENDPOINT_SHA}" + } >> "$GITHUB_OUTPUT" + echo "Computed TAG=${TAG} VERSION=${VERSION} STABLE_BASE=${STABLE_BASE:-} CHANGELOG_BASE=${CHANGELOG_BASE:-}" + # ── end shared version computation ────────────────────────────────── + + - name: Create tag and release + if: steps.ver.outputs.valid == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.ver.outputs.tag }} + IS_RC: ${{ steps.ver.outputs.is_rc }} + CHANGELOG_BASE: ${{ steps.ver.outputs.changelog_base }} + ENDPOINT: ${{ steps.ver.outputs.endpoint }} + MERGE_SHA: ${{ github.sha }} + OWNER: ${{ github.repository_owner }} + REPO_NAME: ${{ github.event.repository.name }} + run: | + set -uo pipefail + if gh release view "$TAG" >/dev/null 2>&1; then + echo "Release ${TAG} already exists; nothing to do." + exit 0 + fi + + # All commits except github-actions[bot], as " by ". + JQ=' + def link($login; $name): + if ($login | type) == "string" and $login != "" + then "[\($login)](https://github.com/\($login))" else $name end; + def colog($email): + ($email // "") + | if test("^[0-9]+\\+[^@]+@users\\.noreply\\.github\\.com$"; "i") + then capture("^[0-9]+\\+(?[^@]+)@"; "i").l + elif test("^[^@]+@users\\.noreply\\.github\\.com$"; "i") + then capture("^(?[^@]+)@"; "i").l + else null end; + [ .[].commits[] ] | .[] + | select((.parents | length) < 2) + | select(.author.login != "github-actions[bot]") + | (.commit.message | split("\n")[0]) as $subject + | ( [ {login: (.author.login // null), name: .commit.author.name} ] + + ( .commit.message | split("\n") + | map(capture("^co-authored-by:\\s*(?[^<]+?)\\s*<(?[^>]+)>\\s*$"; "i")) + | map({login: colog(.email), name: .name}) ) ) + | map(select(.login != "github-actions[bot]" and .name != "github-actions[bot]")) + | reduce .[] as $a ([]; if any(.[]; .login == $a.login and .name == $a.name) then . else . + [$a] end) + | map(link(.login; .name)) + | "- " + $subject + " by " + join(", ") + ' + if [[ -n "$CHANGELOG_BASE" ]]; then + CMP=$(gh api --paginate --slurp \ + "repos/${OWNER}/${REPO_NAME}/compare/${CHANGELOG_BASE}...${ENDPOINT}" || echo '[]') + CHANGES=$(jq -r "$JQ" <<<"$CMP" || true) + else + CHANGES=$(git log "$ENDPOINT" --no-merges --perl-regexp \ + --author='^(?!github-actions\[bot\]).*$' \ + --pretty=format:'- %s by %an' || true) + fi + + { + echo "### What's Changed:" + if [[ -n "$CHANGES" ]]; then printf '%s\n' "$CHANGES"; else echo "_None_"; fi + if [[ -n "$CHANGELOG_BASE" ]]; then + echo + echo "**Full Changelog**: https://github.com/${OWNER}/${REPO_NAME}/compare/${CHANGELOG_BASE}...${TAG}" + fi + } > notes.md + + echo "----- release notes (${TAG}) -----" + cat notes.md + echo "----------------------------------" + + PRE="" + [[ "$IS_RC" == "true" ]] && PRE="--prerelease" + gh release create "$TAG" \ + --target "$MERGE_SHA" \ + --title "${REPO_NAME} ${TAG}" \ + --notes-file notes.md \ + $PRE diff --git a/.gitignore b/.gitignore index 5dd70b3..4001a1f 100644 --- a/.gitignore +++ b/.gitignore @@ -200,7 +200,27 @@ Settings/host_locale.json MCP/mcp.json Data/ !Apps/Data/ -!Docs/ASLM/content/docs/ASLM-Chat/Apps/Data/ +!Docs/ASLM/content/docs/ASLM-Code/Apps/Data/ +# Hugo landing-page data (collides with the case-insensitive `Data/` rule above). +!Docs/ASLM/data/ + +# Hugo documentation (Docs/ASLM) +Docs/ASLM/assets/jsconfig.json +Docs/ASLM/public/ +Docs/ASLM/resources/ +Docs/ASLM/hugo_stats.json +Docs/ASLM/.hugo_build.lock +Docs/ASLM/tmp/ +Docs/ASLM/cache/ +Docs/ASLM/_modules/ +Docs/ASLM/_vendor/ +Docs/ASLM/themes/github.com/ +Docs/ASLM/themes/gohugoio/ +Docs/ASLM/themes/hugo-mod-*/ +Docs/ASLM/go.work +Docs/ASLM/go.work.sum +!Docs/ASLM/go.mod +!Docs/ASLM/go.sum # Tools (shared) pytest-cache-files-*/ diff --git a/ASLM_Module.json b/ASLM_Module.json index ba4b7fb..04ccc69 100644 --- a/ASLM_Module.json +++ b/ASLM_Module.json @@ -3,7 +3,7 @@ "id": "aslm-code", "name": "ASLM Code", "description": "ASLM Code Module - coding assistant UI with LLM inference delegated to ASLM-Chat", - "version": "0.1.0.0", + "version": "0.1.1.10", "author": "NGGT-ASLM", "type": "ui", "category": [ diff --git a/Docs/ASLM/archetypes/code-reference.md b/Docs/ASLM/archetypes/code-reference.md new file mode 100644 index 0000000..9d25339 --- /dev/null +++ b/Docs/ASLM/archetypes/code-reference.md @@ -0,0 +1,50 @@ +--- +title: "{{ replace .File.ContentBaseName "-" " " | title }}" +draft: false +--- + +## Class `TypeName` + +`path/to/Source.cs` — **`access`** — one-line summary. + +--- + +### Constants + +| Name | Value | Description | +| --- | --- | --- | +| | | | + +--- + +### Fields + +| Name | Type | Description | +| --- | --- | --- | +| | | | + +--- + +## Public methods + +#### `public ReturnType MethodName(ParamType param)` + +**Purpose:** What the member does. + +| Step | Action | +| --- | --- | +| 1 | | + +--- + +## Private methods + +#### `private ReturnType HelperName()` + +**Purpose:** What the helper does. + +--- + +## Related + +- [RelatedType](../RelatedType/) diff --git a/Docs/ASLM/archetypes/default.md b/Docs/ASLM/archetypes/default.md new file mode 100644 index 0000000..25b6752 --- /dev/null +++ b/Docs/ASLM/archetypes/default.md @@ -0,0 +1,5 @@ ++++ +date = '{{ .Date }}' +draft = true +title = '{{ replace .File.ContentBaseName "-" " " | title }}' ++++ diff --git a/Docs/ASLM/archetypes/docs-section.md b/Docs/ASLM/archetypes/docs-section.md new file mode 100644 index 0000000..b1366e6 --- /dev/null +++ b/Docs/ASLM/archetypes/docs-section.md @@ -0,0 +1,7 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +draft: false +# Sidebar order among top-level /docs/ sections (lower = higher). Also used inside Patch Notes. +weight: 50 +icon: "folder" +--- diff --git a/Docs/ASLM/archetypes/javascript-reference.md b/Docs/ASLM/archetypes/javascript-reference.md new file mode 100644 index 0000000..6aa156b --- /dev/null +++ b/Docs/ASLM/archetypes/javascript-reference.md @@ -0,0 +1,40 @@ +--- +title: "{{ replace .File.ContentBaseName "-" " " | title }}" +draft: false +--- + +## File `file_name` + +`path/to/file.js` — one-line summary. + +--- + +## Overview + +Optional role in the chat UI. + +--- + +## Public functions + +#### `function functionName(arg)` + +**Purpose:** What the function does. + +**Steps:** + +1. First step. + +--- + +## Private functions + +#### `function _helper()` + +**Purpose:** Internal helper. + +--- + +## Related + +- [parent/_index](_index/) diff --git a/Docs/ASLM/archetypes/patch-notes.md b/Docs/ASLM/archetypes/patch-notes.md new file mode 100644 index 0000000..764c199 --- /dev/null +++ b/Docs/ASLM/archetypes/patch-notes.md @@ -0,0 +1,23 @@ +--- +# File name: YYYYMMDDHHmm-Short-Title.md (date prefix drives sidebar/list order, newest first) +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +description: "A brief summary of the changes in this patch." +--- + +## New Features + +- **[Feature Name]**: A brief description of the new feature. + +## Bug Fixes + +- **[Bug ID/Description]**: A brief description of the bug that was fixed. + +## API Changes + +- **[Module/Function]**: A description of the API change, including any impact on existing code. + +## Known Issues + +- **[Issue ID/Description]**: A description of a known issue and any workarounds. diff --git a/Docs/ASLM/archetypes/python-reference.md b/Docs/ASLM/archetypes/python-reference.md new file mode 100644 index 0000000..48380f2 --- /dev/null +++ b/Docs/ASLM/archetypes/python-reference.md @@ -0,0 +1,57 @@ +--- +title: "{{ replace .File.ContentBaseName "-" " " | title }}" +draft: false +--- + +## Module `module_name` + +`path/to/module.py` — one-line summary. + +--- + +## Overview + +Optional pipeline or role narrative. + +--- + +### Constants + +| Name | Description | +| --- | --- | +| | | + +--- + +## Classes + +### `class ClassName` + +**Purpose:** What the type represents. + +--- + +## Public functions + +#### `def public_function(arg) -> ReturnType` + +**Purpose:** What the function does. + +**Steps:** + +1. First step. +2. Second step. + +--- + +## Private functions + +#### `def _private_helper() -> None` + +**Purpose:** What the helper does. + +--- + +## Related + +- [package/_index](_index/) diff --git a/Docs/ASLM/assets/docs/scss/custom/aslm-overrides.scss b/Docs/ASLM/assets/docs/scss/custom/aslm-overrides.scss new file mode 100644 index 0000000..8aa705f --- /dev/null +++ b/Docs/ASLM/assets/docs/scss/custom/aslm-overrides.scss @@ -0,0 +1,69 @@ +// ASLM documentation typography — calmer hierarchy inside .main-content +.docs-content { + .content-title { + font-size: 1.65rem !important; + line-height: 1.25; + margin-bottom: 0.75rem; + } + + .main-content { + font-size: 0.9375rem; + line-height: 1.55; + + h2 { + font-size: 1.25rem; + font-weight: 600; + margin-top: 1.75rem; + margin-bottom: 0.65rem; + padding-bottom: 0.25rem; + border-bottom: 1px solid var(--gray-300); + } + + h3 { + font-size: 1.05rem; + font-weight: 600; + margin-top: 1.35rem; + margin-bottom: 0.5rem; + } + + h4 { + font-size: 0.9rem; + font-weight: 600; + margin-top: 1rem; + margin-bottom: 0.35rem; + color: var(--text-default); + } + + h5, + h6 { + font-size: 0.85rem; + font-weight: 600; + margin-top: 0.75rem; + margin-bottom: 0.25rem; + } + + // Method signatures in backticks read as code, not giant headings + h4 code, + h5 code { + font-size: 0.82rem; + font-weight: 500; + background: var(--inline-code-bg); + border: var(--inline-code-border); + padding: 0.1rem 0.35rem; + } + + table { + font-size: 0.875rem; + margin-bottom: 1rem; + } + + hr { + margin: 1.5rem 0; + opacity: 0.25; + } + } +} + +[data-dark-mode] .docs-content .main-content h2 { + border-bottom-color: var(--gray-700); +} diff --git a/Docs/ASLM/content/docs/ASLM-Code/API/_index.md b/Docs/ASLM/content/docs/ASLM-Code/API/_index.md new file mode 100644 index 0000000..394e43e --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/API/_index.md @@ -0,0 +1,22 @@ +--- +title: "API" +draft: false +--- + +## Package `API` + +Sources under `API/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [mcp](mcp/) | `mcp.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/API/mcp.md b/Docs/ASLM/content/docs/ASLM-Code/API/mcp.md new file mode 100644 index 0000000..e7e0771 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/API/mcp.md @@ -0,0 +1,648 @@ +--- +title: "mcp" +draft: false +--- + +## Module `mcp` + +`API/mcp.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `API`. See **Related** for package index and callers. + +--- + +## Classes + +### `class AsyncCallableRunner` + +**Purpose:** Type `AsyncCallableRunner` defined in `mcp.py`. + +### `class ExternalWorkerSession` + +**Purpose:** Type `ExternalWorkerSession` defined in `mcp.py`. + +--- + +## Public functions + +#### `def AsyncCallableRunner.__init__() -> None` + +**Purpose:** Initialize the shared runner state. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AsyncCallableRunner.ensure_started() -> None` + +**Purpose:** Start the background loop thread when it is not already running. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AsyncCallableRunner.run(coro, *, timeout=…) -> Any` + +**Purpose:** Run one coroutine on the shared loop and wait for its result. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def AsyncCallableRunner.close() -> None` + +**Purpose:** Stop the background loop and join its thread. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ExternalWorkerSession.__init__(server_file, python_path) -> None` + +**Purpose:** Bind one worker process to a server entrypoint and venv Python. + +**Steps:** + +1. Spawn or communicate with a child process. + +#### `def ExternalWorkerSession.request(operation, payload=…, *, timeout_s=…) -> Any` + +**Purpose:** Send one request to the worker process and return its result. + +#### `def ExternalWorkerSession.close() -> None` + +**Purpose:** Stop the worker process if it is running. + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Iterate and transform or accumulate state. +3. Spawn or communicate with a child process. + +#### `def log_search_tool_io(phase, tool_event, arguments=…, context=…, result=…, error=…, elapsed_seconds=…) -> None` + +**Purpose:** Log exactly what search/read-page tools receive from and return to the model. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def consume_tool_quota(tool_event, counters, arguments=…) -> str | None` + +**Purpose:** Increment one quota counter and return an error message if the call is over limit. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def is_blocking_tool_result(result) -> bool` + +**Purpose:** Return whether a tool result is a guardrail/block message, not fresh evidence. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def forced_final_prompt_after_tool_blocks() -> str` + +**Purpose:** Return the instruction used when the tool loop must stop retrying tools. + +#### `def consume_duplicate_tool_call(tool_event, arguments, seen_signatures) -> str | None` + +**Purpose:** Return an error message when the same quota-controlled tool call repeats. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def consume_tool_cooldown(tool_event, arguments) -> str | None` + +**Purpose:** Block repeated search/read-page calls within a short cooldown window. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def remember_tool_cooldown(tool_event, arguments) -> None` + +**Purpose:** Mark search/read-page calls as recently used. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def consume_read_page_cooldown(tool_event, arguments) -> str | None` + +**Purpose:** Delegate read_page cooldown checks to the shared tool cooldown helper. + +#### `def remember_read_page_cooldown(tool_event, arguments) -> None` + +**Purpose:** Delegate read_page cooldown bookkeeping to the shared tool cooldown helper. + +#### `def reset_cache() -> None` + +**Purpose:** Clear cached discovery so local edits are picked up immediately. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def close_external_workers() -> None` + +**Purpose:** Stop persistent external tool workers owned by this process. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def list_servers(engine=…, model_name=…) -> list[dict[str, Any]]` + +**Purpose:** Return discovered servers that support the current engine and model. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_server(server_id, engine=…, model_name=…) -> dict[str, Any] | None` + +**Purpose:** Return one discovered server when it is available in the current context. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def build_ollama_tools(server_ids, engine=…, model_name=…) -> tuple[list[dict[str, Any]], dict[str, dict[str, Any]]]` + +**Purpose:** Return Ollama-compatible tool payloads for one or more selected servers. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def split_tool_result_payload(content) -> tuple[str, dict[str, Any]]` + +**Purpose:** Split one tool result into model-visible text and UI-only metadata. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def call_ollama_tool(tool_lookup, alias, arguments, context=…) -> str | dict` + +**Purpose:** Execute a local tool and serialize its result for Ollama. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Parse or serialize JSON payloads. + +--- + +## Private functions + +#### `def AsyncCallableRunner._thread_main() -> None` + +**Purpose:** Host the dedicated asyncio loop on a background thread. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `def _get_async_callable_runner() -> AsyncCallableRunner` + +**Purpose:** Return the process-wide async callable runner singleton. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _venv_subprocess_env(python_path) -> dict[str, str]` + +**Purpose:** Return subprocess environment aligned with the selected venv. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ExternalWorkerSession._start() -> None` + +**Purpose:** Spawn the worker process when it is missing or has exited. + +**Steps:** + +1. Spawn or communicate with a child process. + +#### `def ExternalWorkerSession._read_response_line(timeout_s) -> str` + +**Purpose:** Read worker protocol lines until a final envelope arrives. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. +5. Parse or serialize JSON payloads. + +#### `def _print_runtime_event(message) -> None` + +**Purpose:** Emit one console-visible runtime event. + +#### `def _worker_timeout_seconds(operation, payload=…) -> float` + +**Purpose:** Return a wall-clock timeout for one worker request. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _is_debug_logging_enabled() -> bool` + +**Purpose:** Return whether debug-or-higher MCP events should be printed. + +#### `def _is_trace_logging_enabled() -> bool` + +**Purpose:** Return whether trace-level MCP events should be printed. + +#### `def _preview_jsonish(value, limit=…) -> str` + +**Purpose:** Return a compact one-line preview for arguments and results. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _summarize_tool_result(result) -> str` + +**Purpose:** Return a short textual summary of a tool result payload. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _summarize_tool_context(context) -> str` + +**Purpose:** Return a compact summary of the runtime context passed into a tool. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _quota_tool_id(tool_event) -> str` + +**Purpose:** Return the canonical tool id used for per-response quotas. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _search_effort(arguments) -> str` + +**Purpose:** Return the normalized web-search effort value from tool arguments. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _tool_quota_limit(quota_tool_id, arguments=…) -> int` + +**Purpose:** Return the per-response quota for one tool call. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _write_search_io_event(event) -> None` + +**Purpose:** Append complete model/search tool IO as a readable JSON array. + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Parse or serialize JSON payloads. + +#### `def _without_duplicate_preview(value) -> Any` + +**Purpose:** Remove preview fields from diagnostics when they exactly duplicate snippet. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _canonical_tool_arguments(value) -> Any` + +**Purpose:** Return a stable representation for duplicate tool-call detection. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _read_page_urls(arguments) -> list[str]` + +**Purpose:** Extract normalized read_page URL arguments from one tool payload. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _normalize_read_page_url(url) -> str` + +**Purpose:** Normalize one read_page URL for cooldown comparison. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _normalize_cooldown_value(value) -> Any` + +**Purpose:** Normalize one cooldown key payload for stable comparison. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _tool_cooldown_keys(tool_event, arguments) -> list[tuple[str, str]]` + +**Purpose:** Build cooldown keys for one search or read_page tool invocation. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _tool_cooldown_message(tool_id, entries) -> str` + +**Purpose:** Format the duplicate-tool cooldown message shown to the model. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _iter_server_source_files(server_dir)` + +**Purpose:** Yield relevant source files for one local MCP server. + +#### `def _server_signature() -> tuple[tuple[str, int], ...]` + +**Purpose:** Build a stable signature for every local MCP server source file. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _iter_server_files()` + +**Purpose:** Yield top-level MCP server entrypoints from the Tools directory. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def _slugify(value) -> str` + +**Purpose:** Normalize folder and public identifiers into a stable slug. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _purge_modules_under(server_root) -> None` + +**Purpose:** Drop previously imported modules loaded from one tool directory. + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Iterate and transform or accumulate state. + +#### `def _load_module(server_file) -> ModuleType` + +**Purpose:** Load one ``mcp-server.py`` file into an isolated Python module. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _get_worker_python(server_file) -> Path | None` + +**Purpose:** Return the isolated Python executable assigned to one tool server. + +#### `def _get_worker_session(server_file) -> ExternalWorkerSession` + +**Purpose:** Return a long-lived worker session for one external tool server. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _run_worker(server_file, operation, payload=…, *, persistent=…) -> Any` + +**Purpose:** Run a tool worker operation and return its result payload. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. +5. Parse or serialize JSON payloads. +6. Spawn or communicate with a child process. + +#### `def _load_external_server(server_file) -> dict[str, Any]` + +**Purpose:** Load one server definition without importing it into the Django process. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _normalize_schema(schema) -> dict[str, Any]` + +**Purpose:** Return a JSON-schema-like mapping suitable for tool payloads. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _resolve_server_callable(module)` + +**Purpose:** Return the generic server dispatcher when one is exported. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _normalize_tool_handlers(module) -> dict[str, Any]` + +**Purpose:** Return explicit per-tool handlers exported by a server module. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _normalize_server_tools(raw_tools, server_id) -> list[dict[str, Any]]` + +**Purpose:** Validate and normalize tool definitions exposed by one server. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def _merge_user_mcp_servers(discovered) -> None` + +**Purpose:** Append servers from ``MCP/mcp.json`` to the registry payload. + +#### `def _extract_server_definition(module, folder_name, server_file) -> dict[str, Any]` + +**Purpose:** Validate a local MCP module and normalize its public metadata. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def _ensure_registry_loaded() -> dict[str, dict[str, Any]]` + +**Purpose:** Discover and cache valid local MCP-style server modules. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _server_is_supported(server_definition, engine, model_name) -> bool` + +**Purpose:** Return whether a server supports the current engine and model. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _serialize_tool(tool_definition) -> dict[str, Any]` + +**Purpose:** Return the frontend-facing representation of one tool. + +#### `def _serialize_server(server_definition) -> dict[str, Any]` + +**Purpose:** Return the frontend-facing representation of one server. + +**Steps:** + +1. Return the computed result to the caller. + +#### `async def _run_async_callable(callable_fn, *args) -> Any` + +**Purpose:** Execute an async callable with the provided arguments. + +#### `def _run_sync_callable(callable_fn, *args) -> Any` + +**Purpose:** Execute a synchronous callable with the provided arguments. + +#### `def _execute_callable(callable_fn, *args) -> Any` + +**Purpose:** Execute sync and async callables behind one shared helper. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _dispatch_server_callable(callable_fn, tool_id, arguments, context) -> Any` + +**Purpose:** Call a generic server dispatcher with a tolerant signature strategy. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _serialize_tool_result(result) -> str` + +**Purpose:** Convert a tool result into text suitable for a model tool message. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _coerce_tool_result_object(result) -> Any` + +**Purpose:** Parse JSON tool payloads returned as plain strings. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _extract_shared_file_payload(result) -> dict[str, Any] | None` + +**Purpose:** Return a normalized shared-file payload from direct or sandbox-wrapped results. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _extract_structured_tool_result(result) -> dict[str, Any] | None` + +**Purpose:** Return frontend metadata for rich structured tool results. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _image_tool_result_extras(content) -> dict[str, Any]` + +**Purpose:** Build UI-only metadata for an inline image tool result. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _extract_inline_image_payload(result) -> dict[str, Any] | None` + +**Purpose:** Extract an Ollama image payload from the sandbox v2 read envelope. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [API/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/ASLM/_index.md b/Docs/ASLM/content/docs/ASLM-Code/ASLM/_index.md new file mode 100644 index 0000000..74409e6 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/ASLM/_index.md @@ -0,0 +1,25 @@ +--- +title: "ASLM" +draft: false +--- + +## Package `ASLM` + +Sources under `ASLM/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [asgi](asgi/) | `asgi.py` | ASLM Code module | +| [settings](settings/) | `settings.py` | ASLM Code module | +| [urls](urls/) | `urls.py` | ASLM Code module | +| [wsgi](wsgi/) | `wsgi.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/ASLM/asgi.md b/Docs/ASLM/content/docs/ASLM-Code/ASLM/asgi.md new file mode 100644 index 0000000..6b46fcc --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/ASLM/asgi.md @@ -0,0 +1,36 @@ +--- +title: "asgi" +draft: false +--- + +## Module `asgi` + +`ASLM/asgi.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `ASLM`. See **Related** for package index and callers. + +--- + +## Private functions + +#### `def _configure_settings_module() -> None` + +**Purpose:** Set the default Django settings module for ASGI startup. + +#### `def _create_application()` + +**Purpose:** Create the Django ASGI application. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [ASLM/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/ASLM/settings.md b/Docs/ASLM/content/docs/ASLM-Code/ASLM/settings.md new file mode 100644 index 0000000..6e952c3 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/ASLM/settings.md @@ -0,0 +1,20 @@ +--- +title: "settings" +draft: false +--- + +## Module `settings` + +`ASLM/settings.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `ASLM`. See **Related** for package index and callers. + +--- + +## Related + +- [ASLM/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/ASLM/urls.md b/Docs/ASLM/content/docs/ASLM-Code/ASLM/urls.md new file mode 100644 index 0000000..6601a1d --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/ASLM/urls.md @@ -0,0 +1,20 @@ +--- +title: "urls" +draft: false +--- + +## Module `urls` + +`ASLM/urls.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `ASLM`. See **Related** for package index and callers. + +--- + +## Related + +- [ASLM/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/ASLM/wsgi.md b/Docs/ASLM/content/docs/ASLM-Code/ASLM/wsgi.md new file mode 100644 index 0000000..4f54d02 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/ASLM/wsgi.md @@ -0,0 +1,36 @@ +--- +title: "wsgi" +draft: false +--- + +## Module `wsgi` + +`ASLM/wsgi.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `ASLM`. See **Related** for package index and callers. + +--- + +## Private functions + +#### `def _configure_settings_module() -> None` + +**Purpose:** Set the default Django settings module for WSGI startup. + +#### `def _create_application()` + +**Purpose:** Create the Django WSGI application. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [ASLM/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/_index.md new file mode 100644 index 0000000..8bc7777 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/_index.md @@ -0,0 +1,29 @@ +--- +title: "Data" +draft: false +--- + +## Package `Data` + +Sources under `Apps/Data/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [admin](admin/) | `admin.py` | ASLM Code module | +| [apps](apps/) | `apps.py` | ASLM Code module | +| [lms_presets](lms_presets/) | `lms_presets.py` | ASLM Code module | +| [models](models/) | `models.py` | ASLM Code module | +| [ollama_presets](ollama_presets/) | `ollama_presets.py` | ASLM Code module | +| [test_helpers](test_helpers/) | `test_helpers.py` | ASLM Code module | +| [tests](tests/) | `tests.py` | ASLM Code module | +| [views](views/) | `views.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/admin.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/admin.md new file mode 100644 index 0000000..5d11794 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/admin.md @@ -0,0 +1,44 @@ +--- +title: "admin" +draft: false +--- + +## Module `admin` + +`Apps/Data/admin.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Classes + +### `class WorkspaceAdmin` + +**Purpose:** Type `WorkspaceAdmin` defined in `admin.py`. + +### `class ChatAdmin` + +**Purpose:** Type `ChatAdmin` defined in `admin.py`. + +### `class MessageAdmin` + +**Purpose:** Type `MessageAdmin` defined in `admin.py`. + +### `class MessageImageAdmin` + +**Purpose:** Type `MessageImageAdmin` defined in `admin.py`. + +### `class OllamaPresetAdmin` + +**Purpose:** Type `OllamaPresetAdmin` defined in `admin.py`. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/apps.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/apps.md new file mode 100644 index 0000000..77a83de --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/apps.md @@ -0,0 +1,28 @@ +--- +title: "apps" +draft: false +--- + +## Module `apps` + +`Apps/Data/apps.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Classes + +### `class DataConfig` + +**Purpose:** Type `DataConfig` defined in `apps.py`. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/lms_presets.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/lms_presets.md new file mode 100644 index 0000000..a2dc3f3 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/lms_presets.md @@ -0,0 +1,138 @@ +--- +title: "lms_presets" +draft: false +--- + +## Module `lms_presets` + +`Apps/Data/lms_presets.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def normalize_lms_preset_config(config) -> dict[str, Any]` + +**Purpose:** Return a compact LM Studio preset config ready for storage. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ensure_lms_preset_state(model_name) -> tuple[list[LmsPreset], LmsPreset]` + +**Purpose:** Ensure a model has one default preset and one active preset. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def get_lms_preset_payload(model_name) -> dict[str, Any]` + +**Purpose:** Return presets and the active config for the selected model. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def activate_lms_preset(model_name, preset_id) -> dict[str, Any]` + +**Purpose:** Mark one preset as active for its model. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def create_lms_preset(model_name, *, name=…, config=…, activate=…) -> dict[str, Any]` + +**Purpose:** Create a custom preset for the selected model. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def rename_lms_preset(model_name, preset_id, new_name) -> dict[str, Any]` + +**Purpose:** Rename a custom preset without changing its config. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def delete_lms_preset(model_name, preset_id) -> dict[str, Any]` + +**Purpose:** Delete a custom preset and restore the default when needed. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def sync_active_lms_preset(model_name, config) -> dict[str, Any]` + +**Purpose:** Persist UI changes into the active preset. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _normalize_config_value(value) -> Any` + +**Purpose:** Remove empty values while preserving scalar types. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _get_default_lms_preset_config(model_name) -> dict[str, Any]` + +**Purpose:** Read the default LM Studio config baked into the selected model. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _next_custom_preset_name(model_name) -> str` + +**Purpose:** Generate the next free custom preset name for a model. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _serialize_preset(preset) -> dict[str, Any]` + +**Purpose:** Convert a preset model into the frontend JSON shape. + +#### `def _get_preset_by_id(presets, preset_id) -> LmsPreset` + +**Purpose:** Return one preset from a loaded list or raise when it is missing. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/models.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/models.md new file mode 100644 index 0000000..7d3526d --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/models.md @@ -0,0 +1,108 @@ +--- +title: "models" +draft: false +--- + +## Module `models` + +`Apps/Data/models.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Classes + +### `class MessageRole` + +**Purpose:** Type `MessageRole` defined in `models.py`. + +### `class Workspace` + +**Purpose:** Type `Workspace` defined in `models.py`. + +### `class Chat` + +**Purpose:** Type `Chat` defined in `models.py`. + +### `class Message` + +**Purpose:** Type `Message` defined in `models.py`. + +### `class MessageAttachmentKind` + +**Purpose:** Type `MessageAttachmentKind` defined in `models.py`. + +### `class MessageAttachment` + +**Purpose:** Type `MessageAttachment` defined in `models.py`. + +### `class MessageImage` + +**Purpose:** Type `MessageImage` defined in `models.py`. + +### `class OllamaPreset` + +**Purpose:** Type `OllamaPreset` defined in `models.py`. + +### `class LmsPreset` + +**Purpose:** Type `LmsPreset` defined in `models.py`. + +--- + +## Public functions + +#### `def Workspace.__str__() -> str` + +**Purpose:** Implements `Workspace.__str__` in `models.py`. + +#### `def Chat.__str__() -> str` + +**Purpose:** Return the display name for Django admin and logs. + +#### `def Message.__str__() -> str` + +**Purpose:** Return a compact preview of the stored message. + +#### `def MessageAttachment.data_url() -> str` + +**Purpose:** Return the stored attachment as a data URL. + +#### `def MessageAttachment.is_image() -> bool` + +**Purpose:** Return whether the attachment should be treated as an image. + +#### `def MessageAttachment.__str__() -> str` + +**Purpose:** Return a readable label for the related attachment. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def MessageImage.data_url() -> str` + +**Purpose:** Return the stored image as a data URL. + +#### `def MessageImage.__str__() -> str` + +**Purpose:** Return a readable label for the related image. + +#### `def OllamaPreset.__str__() -> str` + +**Purpose:** Return a readable preset name with its model. + +#### `def LmsPreset.__str__() -> str` + +**Purpose:** Return a readable preset name with its model. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/ollama_presets.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/ollama_presets.md new file mode 100644 index 0000000..10eaa06 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/ollama_presets.md @@ -0,0 +1,131 @@ +--- +title: "ollama_presets" +draft: false +--- + +## Module `ollama_presets` + +`Apps/Data/ollama_presets.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def normalize_ollama_preset_config(config) -> dict[str, Any]` + +**Purpose:** Return a compact preset config ready for storage. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def ensure_ollama_preset_state(model_name) -> tuple[list[OllamaPreset], OllamaPreset]` + +**Purpose:** Ensure a model has one default preset and one active preset. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def get_ollama_preset_payload(model_name) -> dict[str, Any]` + +**Purpose:** Return presets and the active config for the selected model. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def activate_ollama_preset(model_name, preset_id) -> dict[str, Any]` + +**Purpose:** Mark one preset as active for its model. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def create_ollama_preset(model_name, *, name=…, config=…, activate=…) -> dict[str, Any]` + +**Purpose:** Create a custom preset for the selected model. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def rename_ollama_preset(model_name, preset_id, new_name) -> dict[str, Any]` + +**Purpose:** Rename a custom preset without changing its config. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def delete_ollama_preset(model_name, preset_id) -> dict[str, Any]` + +**Purpose:** Delete a custom preset and restore the default when needed. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def sync_active_ollama_preset(model_name, config) -> dict[str, Any]` + +**Purpose:** Persist UI changes into the active preset. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _normalize_config_value(value) -> Any` + +**Purpose:** Remove empty values while preserving Ollama scalar types. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _next_custom_preset_name(model_name) -> str` + +**Purpose:** Generate the next free custom preset name for a model. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _serialize_preset(preset) -> dict[str, Any]` + +**Purpose:** Convert a preset model into the frontend JSON shape. + +#### `def _get_preset_by_id(presets, preset_id) -> OllamaPreset` + +**Purpose:** Return one preset from a loaded list or raise when it is missing. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/test_helpers.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/test_helpers.md new file mode 100644 index 0000000..21195a1 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/test_helpers.md @@ -0,0 +1,40 @@ +--- +title: "test_helpers" +draft: false +--- + +## Module `test_helpers` + +`Apps/Data/test_helpers.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def create_test_workspace(*, name=…, path=…) -> Workspace` + +**Purpose:** Create one workspace row for tests. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def create_test_chat(*, workspace=…, **kwargs) -> Chat` + +**Purpose:** Create one chat row bound to a workspace for tests. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/tests.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/tests.md new file mode 100644 index 0000000..530c858 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/tests.md @@ -0,0 +1,364 @@ +--- +title: "tests" +draft: false +--- + +## Module `tests` + +`Apps/Data/tests.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ToolRegistryTestCase` + +**Purpose:** Provide helpers for exercising local ``Tools/*/mcp-server.py`` discovery. + +### `class ChatMessageModelTests` + +**Purpose:** Verify string helpers on persisted chat data. + +### `class MessageImageTests` + +**Purpose:** Verify helper serialization on stored message images. + +### `class MessageAttachmentTests` + +**Purpose:** Verify helper behavior for normalized message attachments. + +### `class OllamaPresetTests` + +**Purpose:** Verify per-model Ollama preset lifecycle helpers. + +### `class LmsPresetTests` + +**Purpose:** Verify per-model LM Studio preset lifecycle helpers. + +### `class LocalServerRegistryTests` + +**Purpose:** Verify discovery and execution of local MCP-style server modules. + +--- + +## Public functions + +#### `def ToolRegistryTestCase.setUp()` + +**Purpose:** Create an isolated tools directory. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolRegistryTestCase.tearDown()` + +**Purpose:** Restore the original registry state. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolRegistryTestCase.write_server(folder, body) -> None` + +**Purpose:** Write a temporary MCP server module. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageAttachmentTests.setUp()` + +**Purpose:** Set up a message for attachment records. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Test methods + +#### `def ChatMessageModelTests.test_chat_and_message_string_representations_are_readable()` + +**Purpose:** Test chat and message string values stay readable. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageImageTests.test_data_url_builds_valid_prefix()` + +**Purpose:** Ensure data URLs include the expected prefix. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageAttachmentTests.test_data_url_and_image_detection_use_stored_metadata()` + +**Purpose:** Ensure data URLs and image detection use stored metadata. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageAttachmentTests.test_attachment_ordering_uses_order_then_id()` + +**Purpose:** Ensure attachment query ordering is stable for the UI. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_ensure_state_creates_default_preset()` + +**Purpose:** Create the default preset when no saved state exists. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_ensure_state_promotes_default_when_no_active_preset_exists()` + +**Purpose:** Promote the default preset when saved state has no active preset. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_ensure_state_keeps_only_one_active_preset()` + +**Purpose:** Deactivate duplicate active presets to keep runtime state deterministic. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_sync_from_default_creates_custom_active_preset()` + +**Purpose:** Clone the default preset when the active config changes. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_sync_unchanged_default_config_does_not_create_custom_preset()` + +**Purpose:** Keep the default preset active when the config has not changed. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_sync_custom_active_preset_updates_in_place()` + +**Purpose:** Update custom active presets in place. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_delete_active_custom_preset_falls_back_to_default()` + +**Purpose:** Fall back to the default preset after deleting the active custom one. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_activate_preset_switches_active_record()` + +**Purpose:** Select a custom preset and deactivate the previous active one. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_default_preset_cannot_be_renamed_or_deleted()` + +**Purpose:** Reject unsafe operations against the default preset. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_sync_drops_unsupported_runtime_keys_from_preset_config()` + +**Purpose:** Drop unsupported runtime keys before saving a preset. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetTests.test_normalize_config_removes_empty_and_unsupported_values()` + +**Purpose:** Normalize compact configs and keep only supported runtime keys. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_ensure_state_creates_default_preset(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_ensure_state_creates_default_preset` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_ensure_state_promotes_default_when_no_active_preset_exists(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_ensure_state_promotes_default_when_no_active_preset_exists` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_sync_from_default_creates_custom_active_preset(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_sync_from_default_creates_custom_active_preset` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_sync_unchanged_default_config_does_not_create_custom_preset(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_sync_unchanged_default_config_does_not_create_custom_preset` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_sync_custom_active_preset_updates_in_place(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_sync_custom_active_preset_updates_in_place` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_delete_active_custom_preset_falls_back_to_default(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_delete_active_custom_preset_falls_back_to_default` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_activate_preset_switches_active_record(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_activate_preset_switches_active_record` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_default_preset_cannot_be_renamed_or_deleted(mock_get_model_settings)` + +**Purpose:** Implements `LmsPresetTests.test_default_preset_cannot_be_renamed_or_deleted` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetTests.test_normalize_config_moves_top_level_options_into_operation()` + +**Purpose:** Normalize legacy top-level options into the operation block. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_list_servers_discovers_valid_server_modules()` + +**Purpose:** Discover valid local server modules. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_supports_filter_hides_servers_for_unsupported_engines()` + +**Purpose:** Hide servers that do not support the requested engine. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_build_ollama_tools_registers_multiple_tools()` + +**Purpose:** Build one OpenAI-style tool entry per local server tool. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_call_ollama_tool_serializes_results_and_passes_context()` + +**Purpose:** Pass context through tool execution and serialize the result. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_invalid_server_modules_are_skipped()` + +**Purpose:** Skip invalid local server modules without breaking discovery. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_tool_handlers_are_supported_without_generic_dispatcher()` + +**Purpose:** Execute servers that expose dedicated tool handlers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_async_tool_handlers_are_supported()` + +**Purpose:** Execute async tool handlers through the sync registry API. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_external_worker_session_skips_heartbeat_lines()` + +**Purpose:** Test persistent workers ignore heartbeat lines and wait for the final envelope. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LocalServerRegistryTests.test_external_worker_session_times_out_silent_worker()` + +**Purpose:** Test a silent persistent worker is killed instead of blocking forever. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `def LocalServerRegistryTests.test_call_ollama_tool_returns_error_for_unknown_alias()` + +**Purpose:** Return a readable error for unknown tool aliases. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/views.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/views.md new file mode 100644 index 0000000..efe0e0f --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/Data/views.md @@ -0,0 +1,20 @@ +--- +title: "views" +draft: false +--- + +## Module `views` + +`Apps/Data/views.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\Data`. See **Related** for package index and callers. + +--- + +## Related + +- [Data/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/_index.md new file mode 100644 index 0000000..b6531dd --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/_index.md @@ -0,0 +1,38 @@ +--- +title: "UI" +draft: false +--- + +## Package `UI` + +Sources under `Apps/UI/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [static](static/) | `Apps/UI/static/` | Submodules | +| [templatetags](templatetags/) | `Apps/UI/templatetags/` | Submodules | +| [admin](admin/) | `admin.py` | ASLM Code module | +| [apps](apps/) | `apps.py` | ASLM Code module | +| [chat_backend](chat_backend/) | `chat_backend.py` | ASLM Code module | +| [file_manifests](file_manifests/) | `file_manifests.py` | ASLM Code module | +| [host_locale_bridge](host_locale_bridge/) | `host_locale_bridge.py` | ASLM Code module | +| [host_theme_bridge](host_theme_bridge/) | `host_theme_bridge.py` | ASLM Code module | +| [locale_catalog](locale_catalog/) | `locale_catalog.py` | ASLM Code module | +| [markitdown_extractor](markitdown_extractor/) | `markitdown_extractor.py` | ASLM Code module | +| [models](models/) | `models.py` | ASLM Code module | +| [run_views](run_views/) | `run_views.py` | ASLM Code module | +| [test_chat_backend](test_chat_backend/) | `test_chat_backend.py` | ASLM Code module | +| [tests](tests/) | `tests.py` | ASLM Code module | +| [upload_storage](upload_storage/) | `upload_storage.py` | ASLM Code module | +| [urls](urls/) | `urls.py` | ASLM Code module | +| [views](views/) | `views.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/admin.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/admin.md new file mode 100644 index 0000000..2f6eb81 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/admin.md @@ -0,0 +1,20 @@ +--- +title: "admin" +draft: false +--- + +## Module `admin` + +`Apps/UI/admin.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/apps.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/apps.md new file mode 100644 index 0000000..1bbb7b3 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/apps.md @@ -0,0 +1,48 @@ +--- +title: "apps" +draft: false +--- + +## Module `apps` + +`Apps/UI/apps.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Classes + +### `class UiConfig` + +**Purpose:** Type `UiConfig` defined in `apps.py`. + +--- + +## Public functions + +#### `def UiConfig.ready() -> None` + +**Purpose:** Implements `UiConfig.ready` in `apps.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Private functions + +#### `def _warmup_aslm_chat() -> None` + +**Purpose:** Warm up ASLM-Chat in the background when ASLM-Code starts inside the host. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/chat_backend.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/chat_backend.md new file mode 100644 index 0000000..0883274 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/chat_backend.md @@ -0,0 +1,93 @@ +--- +title: "chat_backend" +draft: false +--- + +## Module `chat_backend` + +`Apps/UI/chat_backend.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def is_supported_runtime_option_key(option_name) -> bool` + +**Purpose:** Return whether one Ollama Modelfile option can be forwarded as runtime options. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def list_local_tool_server_ids(engine, model_name, tool_server_ids) -> list[str]` + +**Purpose:** Return tool ids that exist in the local Code registry. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def partition_tool_server_ids(engine, model_name, tool_server_ids) -> tuple[list[str], list[str]]` + +**Purpose:** Split one tool selection into local Code tools and Chat-hosted tools. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def resolve_local_tool_servers(engine, model_name, tool_server_ids) -> list[dict[str, Any]]` + +**Purpose:** Resolve selected local tool servers for validation and UI metadata. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def build_chat_generate_payload(*, engine, model_name, llm_messages, system_prompt, session_id, think_value=…, think_level_value=…, clean_options=…, local_tool_server_ids=…, chat_tool_server_ids=…, uploaded_file_ids=…, project_dir=…) -> dict[str, Any]` + +**Purpose:** Build the JSON payload for ASLM-Chat /api/generate/. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def fetch_model_info(engine, model_name) -> dict[str, Any]` + +**Purpose:** Proxy model metadata from ASLM-Chat. + +#### `def fetch_model_settings(engine, model_name) -> dict[str, Any]` + +**Purpose:** Proxy model settings used by legacy metadata extractors. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _serialize_llm_messages_for_chat(llm_messages) -> tuple[list[dict[str, Any]], dict[str, Any] | None]` + +**Purpose:** Convert internal LLM messages into ASLM-Chat /api/generate/ payload shape. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/file_manifests.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/file_manifests.md new file mode 100644 index 0000000..c3e4805 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/file_manifests.md @@ -0,0 +1,171 @@ +--- +title: "file_manifests" +draft: false +--- + +## Module `file_manifests` + +`Apps/UI/file_manifests.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Classes + +### `class UploadedFileManifest` + +**Purpose:** Type `UploadedFileManifest` defined in `file_manifests.py`. + +--- + +## Public functions + +#### `def UploadedFileManifest.to_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable dict for the dataclass. + +#### `def normalize_upload_name(name) -> str` + +**Purpose:** Return a display-safe basename for an uploaded file. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def guess_upload_mime(name, mime=…) -> str` + +**Purpose:** Return a stable MIME value for an uploaded file. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def is_probably_text_upload(name, mime) -> bool` + +**Purpose:** Return whether an upload should be treated as text-like. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def build_uploaded_file_manifest(file_bytes, *, name, mime=…, sandbox_path=…, model_supports_vision=…, file_id=…, tool_server_id=…) -> UploadedFileManifest` + +**Purpose:** Build the model-facing manifest for one uploaded file. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _has_binary_markers(sample) -> bool` + +**Purpose:** Return whether a byte sample contains binary markers. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _decode_text_bytes(file_bytes, *, explicit_text) -> tuple[str, bool]` + +**Purpose:** Decode text bytes. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _looks_like_text(text) -> bool` + +**Purpose:** Return whether decoded text looks printable enough to treat as text. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _trim_text_preview(text, *, source_truncated) -> tuple[str | None, int, bool]` + +**Purpose:** Trim text preview. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_table_preview(name, text) -> str | None` + +**Purpose:** Build table preview. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _build_zip_tree(file_bytes) -> list[str] | None` + +**Purpose:** Build zip tree. + +#### `def _extract_xml_text(xml_bytes) -> str` + +**Purpose:** Extract xml text. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _extract_pdf_text(file_bytes) -> str` + +**Purpose:** Extract pdf text. + +#### `def _extract_docx_text(archive) -> str` + +**Purpose:** Extract docx text. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _extract_pptx_text(archive) -> str` + +**Purpose:** Extract pptx text. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _extract_xlsx_text(archive) -> str` + +**Purpose:** Extract xlsx text. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _extract_document_text(file_bytes, name, mime) -> str` + +**Purpose:** Extract document text. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/host_locale_bridge.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/host_locale_bridge.md new file mode 100644 index 0000000..0327930 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/host_locale_bridge.md @@ -0,0 +1,57 @@ +--- +title: "host_locale_bridge" +draft: false +--- + +## Module `host_locale_bridge` + +`Apps/UI/host_locale_bridge.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def is_rtl_language(language_code) -> bool` + +**Purpose:** Return whether the UI should use right-to-left layout. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def language_to_html_lang(language_code) -> str` + +**Purpose:** Convert BCP-47 to a value suitable for the HTML ``lang`` attribute. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def build_host_locale_template_context() -> dict[str, Any]` + +**Purpose:** Return keys for ``base.html`` and the client locale bootstrap. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _json_for_script_tag(value) -> str` + +**Purpose:** Escape JSON before embedding it in a script tag. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/host_theme_bridge.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/host_theme_bridge.md new file mode 100644 index 0000000..6554733 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/host_theme_bridge.md @@ -0,0 +1,94 @@ +--- +title: "host_theme_bridge" +draft: false +--- + +## Module `host_theme_bridge` + +`Apps/UI/host_theme_bridge.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def normalize_color_to_css(raw) -> str | None` + +**Purpose:** Convert MAUI / ASLM hex strings to a CSS color (``#rrggbb`` or ``rgba(...)``). + +**Steps:** + +1. Return the computed result to the caller. + +#### `def css_color_to_srgb_channels(css) -> tuple[float, float, float] | None` + +**Purpose:** Parse ``#rrggbb`` (from :func:`normalize_color_to_css`) or ``rgba(r,g,b,a)`` into sRGB 0..1. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def infer_prefer_light_activity_surfaces(resolved, fallback_theme) -> bool` + +**Purpose:** Choose light vs dark activity surfaces from the resolved host canvas (not only ``theme``). + +**Steps:** + +1. Return the computed result to the caller. + +#### `def build_host_theme_template_context() -> dict[str, Any]` + +**Purpose:** Return keys for ``base.html``: CSS variable block, color-scheme, optional JSON. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +--- + +## Private functions + +#### `def _effective_theme(payload) -> str` + +**Purpose:** Effective theme. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _srgb_channel_to_linear(c) -> float` + +**Purpose:** Srgb channel to linear. + +#### `def _relative_luminance_srgb(r, g, b) -> float` + +**Purpose:** WCAG relative luminance for sRGB channels in 0..1. + +#### `def _empty_context() -> dict[str, Any]` + +**Purpose:** Empty context. + +#### `def _derived_theme_declarations(prefer_light_surfaces) -> list[str]` + +**Purpose:** Return semantic UI variables that should follow the resolved host palette. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _json_for_script_tag(value) -> str` + +**Purpose:** Return JSON that is safe to embed in an application/json script tag. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/locale_catalog.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/locale_catalog.md new file mode 100644 index 0000000..56af1f1 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/locale_catalog.md @@ -0,0 +1,112 @@ +--- +title: "locale_catalog" +draft: false +--- + +## Module `locale_catalog` + +`Apps/UI/locale_catalog.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def list_available_chat_locales() -> list[str]` + +**Purpose:** Return locale codes that have a catalog file on disk. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def resolve_effective_locale(host_language) -> str` + +**Purpose:** Map host language to a Chat catalog file, falling back to English. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def resolve_effective_locale_from_snapshot() -> str` + +**Purpose:** Resolve effective locale from snapshot. + +#### `def load_catalog(locale) -> dict[str, Any]` + +**Purpose:** Return merged messages for ``locale`` with English as the base layer. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def translate(key, *, locale=…, fallback=…, **params) -> str` + +**Purpose:** Resolve a dot-path key with optional ``{name}`` placeholders. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def catalog_for_js(locale=…) -> dict[str, Any]` + +**Purpose:** Return the merged catalog tree embedded in pages for client-side ``t()``. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _locale_file_path(locale) -> Path` + +**Purpose:** Return the on-disk path for one locale catalog file. + +#### `def _load_raw_catalog(locale) -> dict[str, Any]` + +**Purpose:** Implements `_load_raw_catalog` in `locale_catalog.py`. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _deep_merge(base, overlay) -> dict[str, Any]` + +**Purpose:** Deep merge. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _lookup_nested(catalog, key) -> Any | None` + +**Purpose:** Lookup nested. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _interpolate(template, params) -> str` + +**Purpose:** Interpolate. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/markitdown_extractor.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/markitdown_extractor.md new file mode 100644 index 0000000..d6b9498 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/markitdown_extractor.md @@ -0,0 +1,54 @@ +--- +title: "markitdown_extractor" +draft: false +--- + +## Module `markitdown_extractor` + +`Apps/UI/markitdown_extractor.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def extract_markdown(file_bytes, *, name, mime) -> str` + +**Purpose:** Return Markdown extracted from document bytes, or an empty string on failure. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +--- + +## Private functions + +#### `def _get_markitdown_instance()` + +**Purpose:** Return a shared MarkItDown converter instance when available. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _extract_once(file_bytes, *, name, mime) -> str` + +**Purpose:** Run one MarkItDown conversion for the given bytes. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/models.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/models.md new file mode 100644 index 0000000..e05282e --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/models.md @@ -0,0 +1,20 @@ +--- +title: "models" +draft: false +--- + +## Module `models` + +`Apps/UI/models.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/run_views.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/run_views.md new file mode 100644 index 0000000..b79a20c --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/run_views.md @@ -0,0 +1,78 @@ +--- +title: "run_views" +draft: false +--- + +## Module `run_views` + +`Apps/UI/run_views.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def run_start_api(request)` + +**Purpose:** Start one background run and return its identifier without blocking. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def run_stream_api(request, run_id)` + +**Purpose:** Stream one run's events as newline-delimited JSON, resuming from a sequence. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. +4. Parse or serialize JSON payloads. + +#### `def run_info_api(request, run_id)` + +**Purpose:** Return one run's current metadata snapshot. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def run_abort_api(request, run_id)` + +**Purpose:** Request cooperative cancellation of one run. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _read_json_body(request) -> dict[str, Any]` + +**Purpose:** Parse the JSON request body into a mapping, tolerating empty payloads. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _overrides_from_request(data) -> RunOverrides` + +**Purpose:** Build per-run overrides from the request payload. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/_index.md new file mode 100644 index 0000000..7ab8aca --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/_index.md @@ -0,0 +1,22 @@ +--- +title: "static" +draft: false +--- + +## Package `static` + +Sources under `Apps/UI/static/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [js](js/) | `Apps/UI/static/js/` | Submodules | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/_index.md new file mode 100644 index 0000000..4d360d1 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/_index.md @@ -0,0 +1,24 @@ +--- +title: "js" +draft: false +--- + +## Package `js` + +Sources under `Apps/UI/static/js/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [engines](engines/) | `Apps/UI/static/js/engines/` | Submodules | +| [main](main/) | `Apps/UI/static/js/main/` | Submodules | +| [ui](ui/) | `Apps/UI/static/js/ui/` | Submodules | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/_index.md new file mode 100644 index 0000000..99f6c99 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/_index.md @@ -0,0 +1,27 @@ +--- +title: "engines" +draft: false +--- + +## Package `engines` + +Sources under `Apps/UI/static/js/engines/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [aslm-chat](aslm-chat/) | `aslm-chat.js` | ASLM Code client script | +| [engine-registry](engine-registry/) | `engine-registry.js` | ASLM Code client script | +| [google-genai](google-genai/) | `google-genai.js` | ASLM Code client script | +| [lms](lms/) | `lms.js` | ASLM Code client script | +| [ollama-service](ollama-service/) | `ollama-service.js` | ASLM Code client script | +| [openai](openai/) | `openai.js` | ASLM Code client script | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/aslm-chat.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/aslm-chat.md new file mode 100644 index 0000000..0173d36 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/aslm-chat.md @@ -0,0 +1,28 @@ +--- +title: "aslm-chat" +draft: false +--- + +## File `aslm-chat` + +`Apps/UI/static/js/engines/aslm-chat.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\engines`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `export const aslmChatAdapter` + +**Purpose:** Exported engine adapter object `aslmChatAdapter` registered in [engine-registry](../main/engine-manager/); defines the backend id, labels, and request/stream handlers. + +--- + +## Related + +- [engines/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/engine-registry.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/engine-registry.md new file mode 100644 index 0000000..b4cda6b --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/engine-registry.md @@ -0,0 +1,40 @@ +--- +title: "engine-registry" +draft: false +--- + +## File `engine-registry` + +`Apps/UI/static/js/engines/engine-registry.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\engines`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function normalizeEngineValue(engine)` + +**Purpose:** Client function `normalizeEngineValue` used by the ASLM-Code UI. + +#### `function getEngineAdapter(engine)` + +**Purpose:** Client function `getEngineAdapter` used by the ASLM-Code UI. + +#### `function resolveParameterEngine(facadeEngine, subEngine)` + +**Purpose:** Client function `resolveParameterEngine` used by the ASLM-Code UI. + +#### `function isPresetCapableEngine(engine)` + +**Purpose:** Client function `isPresetCapableEngine` used by the ASLM-Code UI. + +--- + +## Related + +- [engines/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/google-genai.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/google-genai.md new file mode 100644 index 0000000..cd646f1 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/google-genai.md @@ -0,0 +1,28 @@ +--- +title: "google-genai" +draft: false +--- + +## File `google-genai` + +`Apps/UI/static/js/engines/google-genai.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\engines`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `export const googleGenAiAdapter` + +**Purpose:** Exported engine adapter object `googleGenAiAdapter` registered in [engine-registry](../main/engine-manager/); defines the backend id, labels, and request/stream handlers. + +--- + +## Related + +- [engines/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/lms.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/lms.md new file mode 100644 index 0000000..b87fa3d --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/lms.md @@ -0,0 +1,28 @@ +--- +title: "lms" +draft: false +--- + +## File `lms` + +`Apps/UI/static/js/engines/lms.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\engines`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `export const lmsAdapter` + +**Purpose:** Exported engine adapter object `lmsAdapter` registered in [engine-registry](../main/engine-manager/); defines the backend id, labels, and request/stream handlers. + +--- + +## Related + +- [engines/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/ollama-service.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/ollama-service.md new file mode 100644 index 0000000..9bae47c --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/ollama-service.md @@ -0,0 +1,28 @@ +--- +title: "ollama-service" +draft: false +--- + +## File `ollama-service` + +`Apps/UI/static/js/engines/ollama-service.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\engines`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function omitUnsupportedKeys(source)` + +**Purpose:** Client function `omitUnsupportedKeys` used by the ASLM-Code UI. + +--- + +## Related + +- [engines/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/openai.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/openai.md new file mode 100644 index 0000000..1596d84 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/engines/openai.md @@ -0,0 +1,28 @@ +--- +title: "openai" +draft: false +--- + +## File `openai` + +`Apps/UI/static/js/engines/openai.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\engines`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `export const openAiAdapter` + +**Purpose:** Exported engine adapter object `openAiAdapter` registered in [engine-registry](../main/engine-manager/); defines the backend id, labels, and request/stream handlers. + +--- + +## Related + +- [engines/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/_index.md new file mode 100644 index 0000000..7f60503 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/_index.md @@ -0,0 +1,30 @@ +--- +title: "main" +draft: false +--- + +## Package `main` + +Sources under `Apps/UI/static/js/main/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [api](api/) | `api.js` | ASLM Code client script | +| [app-context](app-context/) | `app-context.js` | ASLM Code client script | +| [chat-controller](chat-controller/) | `chat-controller.js` | ASLM Code client script | +| [constants](constants/) | `constants.js` | ASLM Code client script | +| [engine-manager](engine-manager/) | `engine-manager.js` | ASLM Code client script | +| [event-bindings](event-bindings/) | `event-bindings.js` | ASLM Code client script | +| [i18n](i18n/) | `i18n.js` | ASLM Code client script | +| [main](main/) | `main.js` | ASLM Code client script | +| [utils](utils/) | `utils.js` | ASLM Code client script | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/api.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/api.md new file mode 100644 index 0000000..23e04f4 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/api.md @@ -0,0 +1,52 @@ +--- +title: "api" +draft: false +--- + +## File `api` + +`Apps/UI/static/js/main/api.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function getCookie(name)` + +**Purpose:** Client function `getCookie` used by the ASLM-Code UI. + +#### `function getCsrfToken()` + +**Purpose:** Client function `getCsrfToken` used by the ASLM-Code UI. + +#### `function requestJson(url, options)` + +**Purpose:** Client function `requestJson` used by the ASLM-Code UI. + +#### `function getJson(url, options)` + +**Purpose:** Client function `getJson` used by the ASLM-Code UI. + +#### `function postJson(url, payload, options)` + +**Purpose:** Client function `postJson` used by the ASLM-Code UI. + +#### `function patchJson(url, payload, options)` + +**Purpose:** Client function `patchJson` used by the ASLM-Code UI. + +#### `function deleteJson(url, options)` + +**Purpose:** Client function `deleteJson` used by the ASLM-Code UI. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/app-context.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/app-context.md new file mode 100644 index 0000000..1e28ffa --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/app-context.md @@ -0,0 +1,36 @@ +--- +title: "app-context" +draft: false +--- + +## File `app-context` + +`Apps/UI/static/js/main/app-context.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function svgIcon(iconPath, attrs)` + +**Purpose:** Client function `svgIcon` used by the ASLM-Code UI. + +#### `function imageIcon(iconPath, className, altText)` + +**Purpose:** Client function `imageIcon` used by the ASLM-Code UI. + +#### `function createAppContext()` + +**Purpose:** Client function `createAppContext` used by the ASLM-Code UI. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/chat-controller.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/chat-controller.md new file mode 100644 index 0000000..739ed07 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/chat-controller.md @@ -0,0 +1,28 @@ +--- +title: "chat-controller" +draft: false +--- + +## File `chat-controller` + +`Apps/UI/static/js/main/chat-controller.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createChatController(context, dependencies)` + +**Purpose:** Client function `createChatController` used by the ASLM-Code UI. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/constants.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/constants.md new file mode 100644 index 0000000..4b75bf7 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/constants.md @@ -0,0 +1,40 @@ +--- +title: "constants" +draft: false +--- + +## File `constants` + +`Apps/UI/static/js/main/constants.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `export const OLLAMA_UNSUPPORTED_RUNTIME_PARAMS` + +**Purpose:** Runtime parameter keys the Ollama backend does not accept. + +#### `export const THINK_PARAMETER_KEYS` + +**Purpose:** Parameter keys that control model thinking/reasoning behavior. + +#### `export const PARAMETER_DEFINITIONS` + +**Purpose:** Per-parameter metadata (type, range, defaults) for the UI controls. + +#### `export const LLM_PARAMETER_OPTION_SETS` + +**Purpose:** Predefined option sets for selectable LLM parameters. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/engine-manager.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/engine-manager.md new file mode 100644 index 0000000..1eb0a26 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/engine-manager.md @@ -0,0 +1,28 @@ +--- +title: "engine-manager" +draft: false +--- + +## File `engine-manager` + +`Apps/UI/static/js/main/engine-manager.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createEngineManager(context, dependencies)` + +**Purpose:** Client function `createEngineManager` used by the ASLM-Code UI. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/event-bindings.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/event-bindings.md new file mode 100644 index 0000000..c87cb37 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/event-bindings.md @@ -0,0 +1,28 @@ +--- +title: "event-bindings" +draft: false +--- + +## File `event-bindings` + +`Apps/UI/static/js/main/event-bindings.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function bindEventHandlers(context, dependencies)` + +**Purpose:** Client function `bindEventHandlers` used by the ASLM-Code UI. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/i18n.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/i18n.md new file mode 100644 index 0000000..a99b887 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/i18n.md @@ -0,0 +1,52 @@ +--- +title: "i18n" +draft: false +--- + +## File `i18n` + +`Apps/UI/static/js/main/i18n.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function lookupNested(catalog, key)` + +**Purpose:** Client function `lookupNested` used by the ASLM-Code UI. + +#### `function interpolate(template, params)` + +**Purpose:** Client function `interpolate` used by the ASLM-Code UI. + +#### `function initI18n()` + +**Purpose:** Client function `initI18n` used by the ASLM-Code UI. + +#### `function getEffectiveLocale()` + +**Purpose:** Client function `getEffectiveLocale` used by the ASLM-Code UI. + +#### `function isRtl()` + +**Purpose:** Client function `isRtl` used by the ASLM-Code UI. + +#### `function t(key, params, fallback)` + +**Purpose:** Client function `t` used by the ASLM-Code UI. + +#### `function intlLocaleTag()` + +**Purpose:** Client function `intlLocaleTag` used by the ASLM-Code UI. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/main.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/main.md new file mode 100644 index 0000000..10cce4a --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/main.md @@ -0,0 +1,28 @@ +--- +title: "main" +draft: false +--- + +## File `main` + +`Apps/UI/static/js/main/main.js` — ASLM Code client script. + +--- + +## Overview + +Client entry point. Wires the UI factories (app context, controllers, engine manager, UI modules) together once the DOM is ready and binds global event handlers. + +--- + +## Public functions + +#### `function initChatApp()` + +**Purpose:** Bootstrap the page: build the shared context, instantiate the UI and engine modules, and bind global DOM event handlers after the DOM is ready. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/utils.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/utils.md new file mode 100644 index 0000000..d8ce3c2 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/main/utils.md @@ -0,0 +1,76 @@ +--- +title: "utils" +draft: false +--- + +## File `utils` + +`Apps/UI/static/js/main/utils.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\main`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function parseJsonScript(id)` + +**Purpose:** Client function `parseJsonScript` used by the ASLM-Code UI. + +#### `function normalizeParameterName(param)` + +**Purpose:** Client function `normalizeParameterName` used by the ASLM-Code UI. + +#### `function isThinkingParameterKey(param)` + +**Purpose:** Client function `isThinkingParameterKey` used by the ASLM-Code UI. + +#### `function normalizeAddressForParsing(value)` + +**Purpose:** Client function `normalizeAddressForParsing` used by the ASLM-Code UI. + +#### `function isLocalHostname(hostname)` + +**Purpose:** Client function `isLocalHostname` used by the ASLM-Code UI. + +#### `function timeNow(dateInput)` + +**Purpose:** Client function `timeNow` used by the ASLM-Code UI. + +#### `function escHtml(str)` + +**Purpose:** Client function `escHtml` used by the ASLM-Code UI. + +#### `function escapeAttributeValue(str)` + +**Purpose:** Client function `escapeAttributeValue` used by the ASLM-Code UI. + +#### `function escapeTextareaValue(str)` + +**Purpose:** Client function `escapeTextareaValue` used by the ASLM-Code UI. + +#### `function getNestedValue(source, path)` + +**Purpose:** Client function `getNestedValue` used by the ASLM-Code UI. + +#### `function setNestedValue(target, path, value)` + +**Purpose:** Client function `setNestedValue` used by the ASLM-Code UI. + +#### `function deleteNestedValue(target, path)` + +**Purpose:** Client function `deleteNestedValue` used by the ASLM-Code UI. + +#### `function flattenConfigLeaves(source, prefix)` + +**Purpose:** Client function `flattenConfigLeaves` used by the ASLM-Code UI. + +--- + +## Related + +- [main/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/_index.md new file mode 100644 index 0000000..54ea406 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/_index.md @@ -0,0 +1,32 @@ +--- +title: "ui" +draft: false +--- + +## Package `ui` + +Sources under `Apps/UI/static/js/ui/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [attachments-ui](attachments-ui/) | `attachments-ui.js` | ASLM Code client script | +| [browser-portal-ui](browser-portal-ui/) | `browser-portal-ui.js` | ASLM Code client script | +| [chat-history-ui](chat-history-ui/) | `chat-history-ui.js` | ASLM Code client script | +| [citation-preview-ui](citation-preview-ui/) | `citation-preview-ui.js` | ASLM Code client script | +| [citations-ui](citations-ui/) | `citations-ui.js` | ASLM Code client script | +| [messages-ui](messages-ui/) | `messages-ui.js` | ASLM Code client script | +| [model-selector-ui](model-selector-ui/) | `model-selector-ui.js` | ASLM Code client script | +| [parameters-ui](parameters-ui/) | `parameters-ui.js` | ASLM Code client script | +| [skills-ui](skills-ui/) | `skills-ui.js` | ASLM Code client script | +| [tool-inspector](tool-inspector/) | `tool-inspector.js` | ASLM Code client script | +| [workspace-ui](workspace-ui/) | `workspace-ui.js` | ASLM Code client script | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/attachments-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/attachments-ui.md new file mode 100644 index 0000000..41c92f5 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/attachments-ui.md @@ -0,0 +1,28 @@ +--- +title: "attachments-ui" +draft: false +--- + +## File `attachments-ui` + +`Apps/UI/static/js/ui/attachments-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createAttachmentsUi(context)` + +**Purpose:** Client function `createAttachmentsUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/browser-portal-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/browser-portal-ui.md new file mode 100644 index 0000000..e339289 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/browser-portal-ui.md @@ -0,0 +1,28 @@ +--- +title: "browser-portal-ui" +draft: false +--- + +## File `browser-portal-ui` + +`Apps/UI/static/js/ui/browser-portal-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createBrowserPortalUi(context)` + +**Purpose:** Client function `createBrowserPortalUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/chat-history-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/chat-history-ui.md new file mode 100644 index 0000000..086e2b6 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/chat-history-ui.md @@ -0,0 +1,28 @@ +--- +title: "chat-history-ui" +draft: false +--- + +## File `chat-history-ui` + +`Apps/UI/static/js/ui/chat-history-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createChatHistoryUi(context, dependencies)` + +**Purpose:** Client function `createChatHistoryUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/citation-preview-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/citation-preview-ui.md new file mode 100644 index 0000000..a75eae2 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/citation-preview-ui.md @@ -0,0 +1,48 @@ +--- +title: "citation-preview-ui" +draft: false +--- + +## File `citation-preview-ui` + +`Apps/UI/static/js/ui/citation-preview-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function parseCitationPreviewData(chip)` + +**Purpose:** Client function `parseCitationPreviewData` used by the ASLM-Code UI. + +#### `function previewEvidenceLabel(value)` + +**Purpose:** Client function `previewEvidenceLabel` used by the ASLM-Code UI. + +#### `function renderCitationPreviewHtml(data)` + +**Purpose:** Client function `renderCitationPreviewHtml` used by the ASLM-Code UI. + +#### `function fallbackCopyText(text, onDone)` + +**Purpose:** Client function `fallbackCopyText` used by the ASLM-Code UI. + +#### `function copyTextToClipboard(text, onDone)` + +**Purpose:** Client function `copyTextToClipboard` used by the ASLM-Code UI. + +#### `function bindCitationPreviewCards(root)` + +**Purpose:** Client function `bindCitationPreviewCards` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/citations-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/citations-ui.md new file mode 100644 index 0000000..930befe --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/citations-ui.md @@ -0,0 +1,136 @@ +--- +title: "citations-ui" +draft: false +--- + +## File `citations-ui` + +`Apps/UI/static/js/ui/citations-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function isCitationDashCodePoint(codePoint)` + +**Purpose:** Client function `isCitationDashCodePoint` used by the ASLM-Code UI. + +#### `function normalizeCitationHandleGlyphs(value)` + +**Purpose:** Client function `normalizeCitationHandleGlyphs` used by the ASLM-Code UI. + +#### `function normalizeCitationId(value)` + +**Purpose:** Client function `normalizeCitationId` used by the ASLM-Code UI. + +#### `function isCitationHandleId(value)` + +**Purpose:** Client function `isCitationHandleId` used by the ASLM-Code UI. + +#### `function normalizeCitationBrackets(value)` + +**Purpose:** Client function `normalizeCitationBrackets` used by the ASLM-Code UI. + +#### `function normalizeCitationSpacing(value)` + +**Purpose:** Client function `normalizeCitationSpacing` used by the ASLM-Code UI. + +#### `function createCitationRegistry()` + +**Purpose:** Client function `createCitationRegistry` used by the ASLM-Code UI. + +#### `function safeExternalUrl(value)` + +**Purpose:** Client function `safeExternalUrl` used by the ASLM-Code UI. + +#### `function safeFaviconUrl(value)` + +**Purpose:** Client function `safeFaviconUrl` used by the ASLM-Code UI. + +#### `function domainFromUrl(value)` + +**Purpose:** Client function `domainFromUrl` used by the ASLM-Code UI. + +#### `function faviconUrlForDomain(domain)` + +**Purpose:** Client function `faviconUrlForDomain` used by the ASLM-Code UI. + +#### `function readSourceDomain(source)` + +**Purpose:** Client function `readSourceDomain` used by the ASLM-Code UI. + +#### `function fieldFromCitationBlock(block, fieldName)` + +**Purpose:** Client function `fieldFromCitationBlock` used by the ASLM-Code UI. + +#### `function compactText(value, maxLength)` + +**Purpose:** Client function `compactText` used by the ASLM-Code UI. + +#### `function displayTitleForSource(source, domain)` + +**Purpose:** Client function `displayTitleForSource` used by the ASLM-Code UI. + +#### `function normalizeCitationSource(source, rank)` + +**Purpose:** Client function `normalizeCitationSource` used by the ASLM-Code UI. + +#### `function sourceIds(source)` + +**Purpose:** Client function `sourceIds` used by the ASLM-Code UI. + +#### `function collectSourceCandidates(container)` + +**Purpose:** Client function `collectSourceCandidates` used by the ASLM-Code UI. + +#### `function parseToolResultObject(segment)` + +**Purpose:** Client function `parseToolResultObject` used by the ASLM-Code UI. + +#### `function parseTextCitationSources(text)` + +**Purpose:** Client function `parseTextCitationSources` used by the ASLM-Code UI. + +#### `function citationSourceForId(citationRegistry, sourceId)` + +**Purpose:** Client function `citationSourceForId` used by the ASLM-Code UI. + +#### `function addCitationSource(citationRegistry, source, rank)` + +**Purpose:** Client function `addCitationSource` used by the ASLM-Code UI. + +#### `function addSegmentCitationSources(citationRegistry, segment)` + +**Purpose:** Client function `addSegmentCitationSources` used by the ASLM-Code UI. + +#### `function addSegmentsCitationSources(citationRegistry, segments)` + +**Purpose:** Client function `addSegmentsCitationSources` used by the ASLM-Code UI. + +#### `function extractCitationIds(value, citationRegistry)` + +**Purpose:** Client function `extractCitationIds` used by the ASLM-Code UI. + +#### `function hasCitationHandle(value)` + +**Purpose:** Client function `hasCitationHandle` used by the ASLM-Code UI. + +#### `function renderCitationChip(source, sourceId)` + +**Purpose:** Client function `renderCitationChip` used by the ASLM-Code UI. + +#### `function decorateCitationsInHtml(html, citationRegistry)` + +**Purpose:** Client function `decorateCitationsInHtml` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/messages-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/messages-ui.md new file mode 100644 index 0000000..f5c227c --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/messages-ui.md @@ -0,0 +1,28 @@ +--- +title: "messages-ui" +draft: false +--- + +## File `messages-ui` + +`Apps/UI/static/js/ui/messages-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createMessagesUi(context, dependencies)` + +**Purpose:** Client function `createMessagesUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/model-selector-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/model-selector-ui.md new file mode 100644 index 0000000..fd73422 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/model-selector-ui.md @@ -0,0 +1,28 @@ +--- +title: "model-selector-ui" +draft: false +--- + +## File `model-selector-ui` + +`Apps/UI/static/js/ui/model-selector-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createModelSelectorUi(context)` + +**Purpose:** Client function `createModelSelectorUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/parameters-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/parameters-ui.md new file mode 100644 index 0000000..77986fa --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/parameters-ui.md @@ -0,0 +1,28 @@ +--- +title: "parameters-ui" +draft: false +--- + +## File `parameters-ui` + +`Apps/UI/static/js/ui/parameters-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createParametersUi(context)` + +**Purpose:** Client function `createParametersUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/skills-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/skills-ui.md new file mode 100644 index 0000000..ae72f2e --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/skills-ui.md @@ -0,0 +1,28 @@ +--- +title: "skills-ui" +draft: false +--- + +## File `skills-ui` + +`Apps/UI/static/js/ui/skills-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createSkillsUi(context)` + +**Purpose:** Client function `createSkillsUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/tool-inspector.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/tool-inspector.md new file mode 100644 index 0000000..86a5aa8 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/tool-inspector.md @@ -0,0 +1,28 @@ +--- +title: "tool-inspector" +draft: false +--- + +## File `tool-inspector` + +`Apps/UI/static/js/ui/tool-inspector.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createToolInspector(context)` + +**Purpose:** Client function `createToolInspector` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/workspace-ui.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/workspace-ui.md new file mode 100644 index 0000000..e904ca4 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/static/js/ui/workspace-ui.md @@ -0,0 +1,28 @@ +--- +title: "workspace-ui" +draft: false +--- + +## File `workspace-ui` + +`Apps/UI/static/js/ui/workspace-ui.js` — ASLM Code client script. + +--- + +## Overview + +Part of `Apps\UI\static\js\ui`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `function createWorkspaceUi(context)` + +**Purpose:** Client function `createWorkspaceUi` used by the ASLM-Code UI. + +--- + +## Related + +- [ui/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/templatetags/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/templatetags/_index.md new file mode 100644 index 0000000..0d363ee --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/templatetags/_index.md @@ -0,0 +1,22 @@ +--- +title: "templatetags" +draft: false +--- + +## Package `templatetags` + +Sources under `Apps/UI/templatetags/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [i18n_tags](i18n_tags/) | `i18n_tags.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/templatetags/i18n_tags.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/templatetags/i18n_tags.md new file mode 100644 index 0000000..3ab6b67 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/templatetags/i18n_tags.md @@ -0,0 +1,52 @@ +--- +title: "i18n_tags" +draft: false +--- + +## Module `i18n_tags` + +`Apps/UI/templatetags/i18n_tags.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI\templatetags`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def append_static_cache_version(url) -> str` + +**Purpose:** Implements `append_static_cache_version` in `i18n_tags.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def static(path) -> str` + +**Purpose:** Resolve a static asset URL with the per-process cache-bust query. + +#### `def t(context, key) -> str` + +**Purpose:** Translate ``key`` using the effective locale from template context. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def t_param(context, key, **kwargs) -> str` + +**Purpose:** Translate ``key`` with ``{name}`` placeholders. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [templatetags/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/test_chat_backend.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/test_chat_backend.md new file mode 100644 index 0000000..a53f2b7 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/test_chat_backend.md @@ -0,0 +1,84 @@ +--- +title: "test_chat_backend" +draft: false +--- + +## Module `test_chat_backend` + +`Apps/UI/test_chat_backend.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ChatBackendTests` + +**Purpose:** Type `ChatBackendTests` defined in `test_chat_backend.py`. + +--- + +## Test methods + +#### `def ChatBackendTests.test_build_chat_generate_payload_splits_system_and_user() -> None` + +**Purpose:** Implements `ChatBackendTests.test_build_chat_generate_payload_splits_system_and_user` in `test_chat_backend.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatBackendTests.test_partition_tool_server_ids_routes_all_tools_to_chat_without_local_registry() -> None` + +**Purpose:** Implements `ChatBackendTests.test_partition_tool_server_ids_routes_all_tools_to_chat_without_local_registry` in `test_chat_backend.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatBackendTests.test_parse_completed_stream_extracts_visible_text() -> None` + +**Purpose:** Implements `ChatBackendTests.test_parse_completed_stream_extracts_visible_text` in `test_chat_backend.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatBackendTests.test_chat_http_session_adds_csrf_headers_for_post() -> None` + +**Purpose:** Implements `ChatBackendTests.test_chat_http_session_adds_csrf_headers_for_post` in `test_chat_backend.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatBackendTests.test_parse_csrf_from_set_cookie_header() -> None` + +**Purpose:** Implements `ChatBackendTests.test_parse_csrf_from_set_cookie_header` in `test_chat_backend.py`. + +#### `def ChatBackendTests.test_parse_csrf_from_html_input() -> None` + +**Purpose:** Implements `ChatBackendTests.test_parse_csrf_from_html_input` in `test_chat_backend.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatBackendTests.test_invalidate_http_session_clears_cached_csrf_state() -> None` + +**Purpose:** Implements `ChatBackendTests.test_invalidate_http_session_clears_cached_csrf_state` in `test_chat_backend.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/tests.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/tests.md new file mode 100644 index 0000000..875f540 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/tests.md @@ -0,0 +1,1892 @@ +--- +title: "tests" +draft: false +--- + +## Module `tests` + +`Apps/UI/tests.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Classes + +### `class FakeGoogleError` + +**Purpose:** Type `FakeGoogleError` defined in `tests.py`. + +### `class WorkspaceApiTestMixin` + +**Purpose:** Type `WorkspaceApiTestMixin` defined in `tests.py`. + +### `class ToolRegistryTestMixin` + +**Purpose:** Type `ToolRegistryTestMixin` defined in `tests.py`. + +### `class SkillsApiTests` + +**Purpose:** Type `SkillsApiTests` defined in `tests.py`. + +### `class SkillsModelContextTests` + +**Purpose:** Type `SkillsModelContextTests` defined in `tests.py`. + +### `class SkillsSandboxDispatchTests` + +**Purpose:** Type `SkillsSandboxDispatchTests` defined in `tests.py`. + +### `class ToolQuotaTests` + +**Purpose:** Type `ToolQuotaTests` defined in `tests.py`. + +### `class ModelNameExtractionTests` + +**Purpose:** Type `ModelNameExtractionTests` defined in `tests.py`. + +### `class AttachmentNormalizationTests` + +**Purpose:** Type `AttachmentNormalizationTests` defined in `tests.py`. + +### `class AttachmentExtractionTests` + +**Purpose:** Type `AttachmentExtractionTests` defined in `tests.py`. + +### `class UploadedFileManifestTests` + +**Purpose:** Type `UploadedFileManifestTests` defined in `tests.py`. + +### `class UploadFilesApiTests` + +**Purpose:** Type `UploadFilesApiTests` defined in `tests.py`. + +### `class UploadRoutingTests` + +**Purpose:** Type `UploadRoutingTests` defined in `tests.py`. + +### `class StaticCacheVersionTests` + +**Purpose:** Type `StaticCacheVersionTests` defined in `tests.py`. + +### `class MainViewTests` + +**Purpose:** Type `MainViewTests` defined in `tests.py`. + +### `class OllamaOptionMappingTests` + +**Purpose:** Type `OllamaOptionMappingTests` defined in `tests.py`. + +### `class OllamaModelInfoTests` + +**Purpose:** Type `OllamaModelInfoTests` defined in `tests.py`. + +### `class OpenAiOptionMappingTests` + +**Purpose:** Type `OpenAiOptionMappingTests` defined in `tests.py`. + +### `class OpenAiAdapterTests` + +**Purpose:** Type `OpenAiAdapterTests` defined in `tests.py`. + +### `class GoogleGenAiAdapterTests` + +**Purpose:** Type `GoogleGenAiAdapterTests` defined in `tests.py`. + +### `class EngineRegistryTests` + +**Purpose:** Type `EngineRegistryTests` defined in `tests.py`. + +### `class EngineAvailabilitySettingsTests` + +**Purpose:** Type `EngineAvailabilitySettingsTests` defined in `tests.py`. + +### `class LmsAdapterTests` + +**Purpose:** Type `LmsAdapterTests` defined in `tests.py`. + +### `class ViewFormattingTests` + +**Purpose:** Type `ViewFormattingTests` defined in `tests.py`. + +### `class BrowserPortalApiTests` + +**Purpose:** Type `BrowserPortalApiTests` defined in `tests.py`. + +### `class ModelInfoCacheTests` + +**Purpose:** Type `ModelInfoCacheTests` defined in `tests.py`. + +### `class ContextCompressionBudgetTests` + +**Purpose:** Type `ContextCompressionBudgetTests` defined in `tests.py`. + +### `class ChatApiTests` + +**Purpose:** Type `ChatApiTests` defined in `tests.py`. + +### `class GenerateApiTests` + +**Purpose:** Type `GenerateApiTests` defined in `tests.py`. + +### `class LlmApiRuntimeSyncTests` + +**Purpose:** Type `LlmApiRuntimeSyncTests` defined in `tests.py`. + +### `class OllamaDesiredStateTests` + +**Purpose:** Type `OllamaDesiredStateTests` defined in `tests.py`. + +### `class RequestEngineResolutionTests` + +**Purpose:** Type `RequestEngineResolutionTests` defined in `tests.py`. + +### `class DisabledEngineApiTests` + +**Purpose:** Type `DisabledEngineApiTests` defined in `tests.py`. + +### `class RuntimeSettingsApiTests` + +**Purpose:** Type `RuntimeSettingsApiTests` defined in `tests.py`. + +### `class ToolApiTests` + +**Purpose:** Type `ToolApiTests` defined in `tests.py`. + +### `class OllamaPresetApiTests` + +**Purpose:** Type `OllamaPresetApiTests` defined in `tests.py`. + +### `class LmsPresetApiTests` + +**Purpose:** Type `LmsPresetApiTests` defined in `tests.py`. + +### `class MessageIdAndRegenerateTests` + +**Purpose:** Type `MessageIdAndRegenerateTests` defined in `tests.py`. + +--- + +## Public functions + +#### `def FakeGoogleError.__init__(code, status, message, *, details=…) -> None` + +**Purpose:** Implements `FakeGoogleError.__init__` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def WorkspaceApiTestMixin.setUp()` + +**Purpose:** Create one workspace used by chat API requests. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def WorkspaceApiTestMixin.post_chat_api(data, url=…, **kwargs)` + +**Purpose:** Post to chat_api with workspace_id injected into JSON payloads. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def ToolRegistryTestMixin.setUp()` + +**Purpose:** Create an isolated tools directory. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolRegistryTestMixin.tearDown()` + +**Purpose:** Restore the original registry state. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolRegistryTestMixin.write_server(folder, body) -> None` + +**Purpose:** Write a temporary MCP server. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsApiTests.setUp()` + +**Purpose:** Prepare shared fixtures for each test case. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def SkillsApiTests.tearDown()` + +**Purpose:** Clean up fixtures created for each test case. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def SkillsModelContextTests.setUp()` + +**Purpose:** Prepare shared fixtures for each test case. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def SkillsModelContextTests.tearDown()` + +**Purpose:** Clean up fixtures created for each test case. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def UploadFilesApiTests.setUp()` + +**Purpose:** Isolate sandbox writes in a temporary directory. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.tearDown()` + +**Purpose:** Clean up the temporary sandbox. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GoogleGenAiAdapterTests.setUp()` + +**Purpose:** Set up the test fixture. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GoogleGenAiAdapterTests.tearDown()` + +**Purpose:** Tear down the test fixture. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def EngineAvailabilitySettingsTests.tearDown()` + +**Purpose:** Clear the settings cache between mocked settings snapshots. + +#### `def ModelInfoCacheTests.setUp()` + +**Purpose:** Clear metadata caches around each test. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ModelInfoCacheTests.tearDown()` + +**Purpose:** Restore metadata cache state after the test. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.setUp()` + +**Purpose:** Set up the test fixture. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GenerateApiTests.setUp()` + +**Purpose:** Implements `GenerateApiTests.setUp` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def DisabledEngineApiTests.setUp()` + +**Purpose:** Implements `DisabledEngineApiTests.setUp` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def DisabledEngineApiTests.isolated_settings_payload(payload)` + +**Purpose:** Implements `DisabledEngineApiTests.isolated_settings_payload` in `tests.py`. + +#### `def RuntimeSettingsApiTests.setUp()` + +**Purpose:** Implements `RuntimeSettingsApiTests.setUp` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.tearDown()` + +**Purpose:** Implements `RuntimeSettingsApiTests.tearDown` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.isolated_settings_payload(payload)` + +**Purpose:** Isolated settings payload. + +#### `def ToolApiTests.setUp()` + +**Purpose:** Implements `ToolApiTests.setUp` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.tearDown()` + +**Purpose:** Implements `ToolApiTests.tearDown` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.setUp()` + +**Purpose:** Implements `OllamaPresetApiTests.setUp` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.tearDown()` + +**Purpose:** Implements `OllamaPresetApiTests.tearDown` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.setUp()` + +**Purpose:** Implements `LmsPresetApiTests.setUp` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.tearDown()` + +**Purpose:** Implements `LmsPresetApiTests.tearDown` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageIdAndRegenerateTests.setUp()` + +**Purpose:** Prepare shared fixtures for each test case. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Private functions + +#### `def SkillsModelContextTests._assert_has_skills_inventory(text, *folders) -> None` + +**Purpose:** Assert has skills inventory. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def SkillsModelContextTests._assert_no_skill_context(text) -> None` + +**Purpose:** Assert no skill context. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests._assert_config_update_header(text) -> None` + +**Purpose:** Assert config update header. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests._write_skill(folder, *, enabled=…, title=…) -> None` + +**Purpose:** Write skill. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests._compose(*, consume=…, include_baseline=…, user_prompt=…) -> str` + +**Purpose:** Compose. + +#### `def SkillsModelContextTests._system_message_for_chat(system_prompt, user_text=…) -> str` + +**Purpose:** System message for chat. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def SkillsModelContextTests._disable_via_api(folder) -> None` + +**Purpose:** Disable via api. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def EngineAvailabilitySettingsTests._with_settings_payload(payload, assertion)` + +**Purpose:** Run one assertion block against an isolated settings payload. + +#### `def RequestEngineResolutionTests._build_request(query=…)` + +**Purpose:** Implements `RequestEngineResolutionTests._build_request` in `tests.py`. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Test methods + +#### `def SkillsApiTests.test_skills_root_created_and_crud_validates_paths()` + +**Purpose:** Verify skills root created and crud validates paths. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_front_matter_summary_and_prompt_inventory()` + +**Purpose:** Verify front matter summary and prompt inventory. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsApiTests.test_disable_skill_queues_refreshed_inventory_for_next_prompt()` + +**Purpose:** Verify disable skill queues refreshed inventory for next prompt. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_sync_mirrors_skills_and_overrides_sandbox()` + +**Purpose:** Verify sync mirrors skills and overrides sandbox. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsApiTests.test_sync_excludes_disabled_skills_from_sandbox()` + +**Purpose:** Verify sync excludes disabled skills from sandbox. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsApiTests.test_disable_skill_removes_folder_from_sandbox()` + +**Purpose:** Verify disable skill removes folder from sandbox. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_create_skill_subdirectory()` + +**Purpose:** Verify create skill subdirectory. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_create_skill_subdirectory_rejects_duplicate()` + +**Purpose:** Verify create skill subdirectory rejects duplicate. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_create_skill_subdirectory_rejects_traversal()` + +**Purpose:** Verify create skill subdirectory rejects traversal. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_create_skill_subdirectory_rejects_file_extension()` + +**Purpose:** Verify create skill subdirectory rejects file extension. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_rename_and_delete_skill_subdirectory()` + +**Purpose:** Verify rename and delete skill subdirectory. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_rename_skill_file()` + +**Purpose:** Verify rename skill file. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_import_skill_creates_folder_and_files()` + +**Purpose:** Verify import skill creates folder and files. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsApiTests.test_import_skill_merges_into_existing_folder()` + +**Purpose:** Verify import skill merges into existing folder. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsModelContextTests.test_enabled_skills_appear_only_on_first_chat_turn()` + +**Purpose:** Verify enabled skills appear only on first chat turn. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests.test_chat_api_first_turn_includes_skills_baseline()` + +**Purpose:** Verify chat api first turn includes skills baseline. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests.test_static_disabled_skill_is_omitted_from_inventory()` + +**Purpose:** Verify static disabled skill is omitted from inventory. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests.test_disable_sends_updated_inventory_once()` + +**Purpose:** Verify disable sends updated inventory once. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests.test_context_usage_style_compose_does_not_consume_pending_refresh()` + +**Purpose:** Verify context usage style compose does not consume pending refresh. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def SkillsModelContextTests.test_enable_queues_refreshed_inventory_with_enabled_skill()` + +**Purpose:** Verify enable queues refreshed inventory with enabled skill. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsModelContextTests.test_re_toggle_without_change_does_not_queue_refresh()` + +**Purpose:** Verify re toggle without change does not queue refresh. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsModelContextTests.test_toggle_still_queues_inventory_when_sandbox_sync_fails(_sync_mock)` + +**Purpose:** Verify toggle still queues inventory when sandbox sync fails. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def SkillsSandboxDispatchTests.test_sandbox_tool_dispatch_syncs_skills_first()` + +**Purpose:** Verify sandbox tool dispatch syncs skills first. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolQuotaTests.test_high_effort_web_search_limits_to_three_calls()` + +**Purpose:** High-effort web search is expensive, so keep it bounded per response. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolQuotaTests.test_normal_web_search_keeps_default_quota()` + +**Purpose:** Lower-effort searches keep the existing broader budget. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def ModelNameExtractionTests.test_extracts_name_from_string()` + +**Purpose:** Test extracts name from string. + +#### `def ModelNameExtractionTests.test_extracts_name_from_mapping()` + +**Purpose:** Test extracts name from mapping. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ModelNameExtractionTests.test_prefers_id_over_friendly_name()` + +**Purpose:** Test prefers id over friendly name. + +#### `def AttachmentNormalizationTests.test_invalid_base64_attachments_are_ignored()` + +**Purpose:** Test invalid base64 attachments are ignored before persistence. + +#### `def AttachmentNormalizationTests.test_data_url_attachments_are_normalized_for_storage()` + +**Purpose:** Test data URL attachments keep MIME, filename and decoded size. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AttachmentNormalizationTests.test_legacy_image_payloads_are_normalized_with_detected_mime()` + +**Purpose:** Test legacy image payloads are detected and named. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AttachmentNormalizationTests.test_attachment_order_uses_surviving_items_only()` + +**Purpose:** Test empty entries are skipped without breaking later order values. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AttachmentExtractionTests.test_text_attachment_extraction_is_cached_on_record()` + +**Purpose:** Cache extracted text back onto the attachment record. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AttachmentExtractionTests.test_cached_attachment_text_is_reused()` + +**Purpose:** Reuse cached text without trying to decode a broken payload. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_text_manifest_uses_bounded_preview()` + +**Purpose:** Test text files expose bounded previews instead of unbounded content. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_binary_manifest_does_not_expose_text_preview()` + +**Purpose:** Test binary-looking files do not get decoded through permissive encodings. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_upload_name_is_normalized_to_basename()` + +**Purpose:** Test uploaded names are reduced to safe basenames. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_zip_manifest_includes_archive_tree()` + +**Purpose:** Test zip files include a bounded archive tree without unpacking. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_pdf_manifest_extracts_text_layer()` + +**Purpose:** Test PDF files with a text layer expose a model-readable preview. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_docx_manifest_extracts_document_xml_text()` + +**Purpose:** Test docx files expose text from their document XML. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_pptx_manifest_extracts_slide_text()` + +**Purpose:** Test pptx files expose slide text from their slide XML. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_xlsx_manifest_extracts_sheet_text()` + +**Purpose:** Test xlsx files expose a small table preview from worksheet XML. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadedFileManifestTests.test_non_vision_image_manifest_keeps_sandbox_without_text()` + +**Purpose:** Test non-vision image uploads keep metadata and sandbox access only. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_upload_api_returns_public_file_card_payload_only()` + +**Purpose:** Test the upload API returns only card-safe fields while storing a private manifest. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def UploadFilesApiTests.test_upload_api_labels_zip_archive_for_card()` + +**Purpose:** Test archive uploads get a simple English card label. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_upload_api_accepts_unknown_extension_as_generic_file()` + +**Purpose:** Test unusual extensions are accepted and routed as generic files. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def UploadFilesApiTests.test_upload_limit_is_16_gb()` + +**Purpose:** Test the configured upload ceiling matches the advertised large-video contract. + +#### `def UploadFilesApiTests.test_upload_api_uses_lightweight_manifest_after_inline_threshold()` + +**Purpose:** Test uploads beyond the inline manifest threshold are stored without full in-memory extraction. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def UploadFilesApiTests.test_upload_api_reports_oversized_files()` + +**Purpose:** Test oversize uploads are rejected before being stored. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_uploaded_file_content_supports_suffix_byte_range()` + +**Purpose:** Test media content endpoint supports suffix ranges needed by MP4 metadata reads. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_uploaded_file_content_chunks_open_ended_range()` + +**Purpose:** Test open-ended media ranges are chunked so playback can start without reading the rest of a large file. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_shared_file_download_supports_byte_range()` + +**Purpose:** Test model-shared files use the same range streaming path as uploaded files. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `def UploadFilesApiTests.test_shared_file_download_rejects_project_absolute_path()` + +**Purpose:** Test shared-file downloads are limited to the sandbox workspace. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_shared_file_download_allows_container_sandbox_path()` + +**Purpose:** Test container-style sandbox paths are still mapped to the host sandbox. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `def UploadFilesApiTests.test_upload_api_requires_files()` + +**Purpose:** Test empty upload requests fail before returning a card payload. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_model_upload_manifest_respects_sandbox_selection()` + +**Purpose:** Test model-facing upload manifests do not expose sandbox paths unless selected. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_uploaded_file_prompt_block_hides_disabled_sandbox_path()` + +**Purpose:** Test the private prompt block only includes sandbox path when allowed. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_uploaded_archive_prompt_block_says_preview_not_extracted()` + +**Purpose:** Verify uploaded archive prompt block says preview not extracted. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_uploaded_file_ids_are_normalized_from_request_shapes()` + +**Purpose:** Test upload file ids can be read from current and future request shapes. + +#### `def UploadFilesApiTests.test_uploaded_file_context_entry_round_trips_file_ids()` + +**Purpose:** Test upload ids can be persisted on a user message for regenerate/history replay. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadFilesApiTests.test_selected_tools_include_sandbox_only_when_resolved()` + +**Purpose:** Test sandbox state is derived only from resolved tool servers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def UploadRoutingTests.test_display_kind_routes_known_file_types()` + +**Purpose:** Test routing common file types to stable card labels. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def UploadRoutingTests.test_display_kind_routes_unknown_extension_to_file()` + +**Purpose:** Test unknown extensions fall back to generic File, not rejection. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def StaticCacheVersionTests.test_static_cache_version_format()` + +**Purpose:** Verify static cache version format. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def StaticCacheVersionTests.test_static_template_tag_appends_cache_bust_query()` + +**Purpose:** Verify static template tag appends the cache-bust query. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MainViewTests.test_main_view_includes_runtime_settings_and_local_servers(_mock_engine)` + +**Purpose:** Verify main view includes runtime settings and local servers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaOptionMappingTests.test_prepare_chat_kwargs_maps_think_level_into_think()` + +**Purpose:** Test prepare chat kwargs maps think level into think. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaOptionMappingTests.test_prepare_chat_kwargs_drops_runtime_options_unsupported_by_current_ollama()` + +**Purpose:** Test prepare chat kwargs drops runtime options unsupported by current Ollama. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaOptionMappingTests.test_prepare_chat_kwargs_ignores_lms_only_internal_keys()` + +**Purpose:** Test prepare chat kwargs ignores LM Studio only internal keys. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaOptionMappingTests.test_prepare_runtime_passes_requested_engine_to_managed_service(mock_get_service)` + +**Purpose:** Verify prepare runtime passes requested engine to managed service. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaModelInfoTests.test_ollama_capabilities_without_tools_disable_tool_support()` + +**Purpose:** Test an explicit Ollama capabilities list without tools disables tool support. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaModelInfoTests.test_ollama_tools_capability_enables_tool_support()` + +**Purpose:** Test Ollama's tools capability enables support without template markers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaModelInfoTests.test_ollama_tool_template_fallback_when_capabilities_are_missing()` + +**Purpose:** Test old/custom Ollama responses can still infer tools from the template. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OpenAiOptionMappingTests.test_maps_supported_options_and_keeps_custom_values_in_extra_body()` + +**Purpose:** Test maps supported options and keeps custom values in extra body. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OpenAiOptionMappingTests.test_openai_client_uses_placeholder_api_key_when_not_configured(_mock_api_key, _mock_engine_url, mock_openai_client)` + +**Purpose:** Verify openai client uses placeholder api key when not configured. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OpenAiAdapterTests.test_get_model_settings_reads_openai_capabilities_and_reasoning(mock_get_client)` + +**Purpose:** Verify get model settings reads openai capabilities and reasoning. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OpenAiAdapterTests.test_get_model_settings_reads_direct_feature_flags_and_scalar_supported_parameters(mock_get_client)` + +**Purpose:** Verify get model settings reads direct feature flags and scalar supported parameters. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OpenAiAdapterTests.test_generate_stream_parses_reasoning_and_visible_content(mock_get_client)` + +**Purpose:** Verify generate stream parses reasoning and visible content. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OpenAiAdapterTests.test_generate_stream_does_not_duplicate_plain_content_into_thinking(mock_get_client)` + +**Purpose:** Verify generate stream does not duplicate plain content into thinking. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OpenAiAdapterTests.test_get_model_settings_reads_companion_metadata_without_generation(mock_get_client, mock_get_companion_payload)` + +**Purpose:** Verify get model settings reads companion metadata without generation. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GoogleGenAiAdapterTests.test_function_call_history_preserves_thought_signature()` + +**Purpose:** Test Gemini function-call replay preserves thought signatures. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GoogleGenAiAdapterTests.test_preserved_function_call_parts_avoid_unsigned_duplicate()` + +**Purpose:** Test fallback function-call reconstruction is skipped for preserved Gemini parts. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def GoogleGenAiAdapterTests.test_unsigned_legacy_function_call_history_is_skipped()` + +**Purpose:** Test legacy unsigned Gemini tool-call transcript is not replayed. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def GoogleGenAiAdapterTests.test_get_models_filters_out_non_generate_content_models(mock_get_client, _mock_close_client)` + +**Purpose:** Verify get models filters out non generate content models. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GoogleGenAiAdapterTests.test_get_models_hides_zero_quota_models_for_current_key_after_runtime_learning(_mock_api_key, _mock_engine_url, mock_get_client, _mock_close_client)` + +**Purpose:** Verify get models hides zero quota models for current key after runtime learning. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GoogleGenAiAdapterTests.test_get_models_keeps_temporarily_rate_limited_models_visible(_mock_api_key, _mock_engine_url, mock_get_client, _mock_close_client)` + +**Purpose:** Verify get models keeps temporarily rate limited models visible. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GoogleGenAiAdapterTests.test_get_model_settings_returns_toggle_when_thinking_level_is_unsupported(mock_get_client, _mock_close_client)` + +**Purpose:** Verify get model settings returns toggle when thinking level is unsupported. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def GoogleGenAiAdapterTests.test_generate_retries_without_thinking_level_when_model_rejects_it(mock_get_client, _mock_close_client)` + +**Purpose:** Verify generate retries without thinking level when model rejects it. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def GoogleGenAiAdapterTests.test_learned_availability_is_scoped_to_api_key(_mock_engine_url, mock_get_client, _mock_close_client)` + +**Purpose:** Verify learned availability is scoped to api key. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def EngineRegistryTests.test_reload_model_raises_for_engines_without_reload_support()` + +**Purpose:** Test reload model raises for engines without reload support. + +#### `def EngineRegistryTests.test_get_models_prepares_runtime_before_listing(mock_get_engine_module, mock_prepare_runtime)` + +**Purpose:** Verify get models prepares runtime before listing. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def EngineRegistryTests.test_get_model_settings_prepares_runtime_before_loading_metadata(mock_get_engine_module, mock_prepare_runtime)` + +**Purpose:** Verify get model settings prepares runtime before loading metadata. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def EngineAvailabilitySettingsTests.test_supported_engines_only_includes_enabled_flags()` + +**Purpose:** Test supported engines only includes enabled engine flags. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def EngineAvailabilitySettingsTests.test_active_engine_falls_back_when_configured_engine_is_disabled()` + +**Purpose:** Test disabled active engine falls back to the first enabled engine. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsAdapterTests.test_serialize_model_info_reads_nested_info_wrapper()` + +**Purpose:** Test serialize model info reads nested info wrapper. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsAdapterTests.test_get_model_settings_uses_loaded_model_info_when_direct_lookup_fails(mock_get_client, _mock_close_client)` + +**Purpose:** Verify get model settings uses loaded model info when direct lookup fails. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsAdapterTests.test_prepare_openai_prediction_options_keeps_lms_custom_values_in_extra_body()` + +**Purpose:** Test prepare OpenAI prediction options keeps LM Studio custom values in extra body. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ViewFormattingTests.test_strip_llm_control_tokens_removes_service_markers()` + +**Purpose:** Test strip LLM control tokens removes service markers. + +#### `def ViewFormattingTests.test_format_runtime_error_hides_lms_model_load_verbosity()` + +**Purpose:** Test format runtime error hides LM Studio model load verbosity. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ViewFormattingTests.test_build_chat_title_handles_long_and_attachment_only_messages()` + +**Purpose:** Test chat titles are compact and useful for attachment-only threads. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ViewFormattingTests.test_parse_active_tool_slugs_supports_json_and_legacy_values()` + +**Purpose:** Test active tool slugs support both current JSON and legacy string shapes. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ViewFormattingTests.test_shared_file_tool_result_keeps_ui_metadata()` + +**Purpose:** Test shared files keep their UI render payload after tool result splitting. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ViewFormattingTests.test_build_activity_segments_keeps_repeated_share_file_aliases()` + +**Purpose:** Test repeated tool aliases preserve all shared files in activity segments. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def BrowserPortalApiTests.test_active_browser_portal_state_uses_deadline_when_available()` + +**Purpose:** Verify active browser portal state uses deadline when available. + +#### `def BrowserPortalApiTests.test_finish_event_response_reports_done_and_queues_event()` + +**Purpose:** Verify finish event response reports done and queues event. + +#### `def ModelInfoCacheTests.test_model_info_payload_cache_returns_detached_copies(mock_get_model_settings)` + +**Purpose:** Verify model info payload cache returns detached copies. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ContextCompressionBudgetTests.test_history_budget_uses_same_model_token_estimator_as_usage_ui()` + +**Purpose:** Verify history budget uses same model token estimator as usage ui. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ContextCompressionBudgetTests.test_history_budget_blends_observed_token_ratio()` + +**Purpose:** Verify history budget blends observed token ratio. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_rejects_invalid_json_body()` + +**Purpose:** Test chat API rejects invalid JSON before touching runtime services. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_rejects_missing_model()` + +**Purpose:** Test chat API requires a model name. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_creates_new_chat_and_streams_response(_mock_engine, mock_generate, mock_prepare_runtime)` + +**Purpose:** Verify chat api creates new chat and streams response. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_creates_attachment_only_thread(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api creates attachment only thread. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def ChatApiTests.test_chat_api_passes_selected_tool_server_to_ollama(_mock_engine, mock_generate, _mock_prepare_runtime, _mock_model_settings)` + +**Purpose:** Verify chat api passes selected tool server to ollama. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_rejects_unknown_tool_server(_mock_engine)` + +**Purpose:** Verify chat api rejects unknown tool server. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_stream_includes_server_and_tool_markers(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api stream includes server and tool markers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_persists_reasoning_only_response(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api persists reasoning only response. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_buffers_reasoning_while_streaming(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api buffers reasoning while streaming. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_stream_chat_response_auto_compresses_at_reasoning_safe_point(mock_generate, _mock_prepare_runtime, mock_build_compression_event)` + +**Purpose:** Verify stream chat response auto compresses at reasoning safe point. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_stream_chat_response_auto_compresses_at_tool_call_safe_point(mock_generate, _mock_prepare_runtime, mock_build_compression_event)` + +**Purpose:** Verify stream chat response auto compresses at tool call safe point. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_build_chat_history_compresses_when_current_prompt_crosses_threshold(mock_build_summary)` + +**Purpose:** Verify build chat history compresses when current prompt crosses threshold. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_persists_generic_attachments_and_builds_lms_messages(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api persists generic attachments and builds lms messages. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def ChatApiTests.test_chat_api_rejects_tool_server_when_lms_model_lacks_tool_support(_mock_engine, _mock_model_settings, _mock_preset_model_settings)` + +**Purpose:** Verify chat api rejects tool server when lms model lacks tool support. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_rejects_tool_server_when_ollama_capabilities_omit_tools(_mock_engine, _mock_model_settings)` + +**Purpose:** Verify chat api rejects tool server when ollama capabilities omit tools. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_rejects_tool_server_when_openai_model_lacks_tool_support(_mock_engine, _mock_model_settings)` + +**Purpose:** Verify chat api rejects tool server when openai model lacks tool support. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_saves_visible_content_and_machine_transcript(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api saves visible content and machine transcript. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_uses_stored_transcript_for_follow_up_messages(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api uses stored transcript for follow up messages. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_strips_legacy_ui_markup_when_transcript_is_missing(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api strips legacy ui markup when transcript is missing. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatApiTests.test_chat_api_strips_service_control_tokens_from_visible_output(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Verify chat api strips service control tokens from visible output. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GenerateApiTests.test_generate_api_streams_without_db_writes(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Implements `GenerateApiTests.test_generate_api_streams_without_db_writes` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GenerateApiTests.test_generate_api_passes_messages_to_generate(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Implements `GenerateApiTests.test_generate_api_passes_messages_to_generate` in `tests.py`. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def GenerateApiTests.test_generate_api_rejects_missing_model()` + +**Purpose:** Implements `GenerateApiTests.test_generate_api_rejects_missing_model` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def GenerateApiTests.test_generate_api_supports_inline_attachments(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Implements `GenerateApiTests.test_generate_api_supports_inline_attachments` in `tests.py`. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def GenerateApiTests.test_generate_api_passes_tool_servers_to_generate(_mock_engine, mock_generate, _mock_prepare_runtime, _mock_model_settings)` + +**Purpose:** Implements `GenerateApiTests.test_generate_api_passes_tool_servers_to_generate` in `tests.py`. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def GenerateApiTests.test_generate_api_replays_llm_transcript_in_history(_mock_engine, mock_generate, _mock_prepare_runtime)` + +**Purpose:** Implements `GenerateApiTests.test_generate_api_replays_llm_transcript_in_history` in `tests.py`. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def LlmApiRuntimeSyncTests.test_sync_prepares_enabled_and_cleans_up_disabled(_mock_enabled, mock_prepare, mock_cleanup)` + +**Purpose:** Implements `LlmApiRuntimeSyncTests.test_sync_prepares_enabled_and_cleans_up_disabled` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LlmApiRuntimeSyncTests.test_handle_engine_transition_calls_sync(mock_sync)` + +**Purpose:** Implements `LlmApiRuntimeSyncTests.test_handle_engine_transition_calls_sync` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaDesiredStateTests.test_desired_state_runs_when_enabled_even_if_active_engine_differs(_mock_get, _mock_active)` + +**Purpose:** Implements `OllamaDesiredStateTests.test_desired_state_runs_when_enabled_even_if_active_engine_differs` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RequestEngineResolutionTests.test_resolve_defaults_to_active_engine(_mock_active)` + +**Purpose:** Implements `RequestEngineResolutionTests.test_resolve_defaults_to_active_engine` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RequestEngineResolutionTests.test_resolve_query_engine_when_enabled(_mock_enabled)` + +**Purpose:** Implements `RequestEngineResolutionTests.test_resolve_query_engine_when_enabled` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RequestEngineResolutionTests.test_resolve_rejects_disabled_engine(_mock_enabled)` + +**Purpose:** Implements `RequestEngineResolutionTests.test_resolve_rejects_disabled_engine` in `tests.py`. + +#### `def RequestEngineResolutionTests.test_body_engine_takes_priority_over_query(_mock_enabled)` + +**Purpose:** Implements `RequestEngineResolutionTests.test_body_engine_takes_priority_over_query` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def DisabledEngineApiTests.test_models_api_rejects_disabled_engine()` + +**Purpose:** Implements `DisabledEngineApiTests.test_models_api_rejects_disabled_engine` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def DisabledEngineApiTests.test_chat_api_accepts_engine_query_param(mock_generate, _mock_prepare_runtime)` + +**Purpose:** Implements `DisabledEngineApiTests.test_chat_api_accepts_engine_query_param` in `tests.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_get_runtime_settings_payload()` + +**Purpose:** Test get runtime settings payload. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_runtime_settings_rejects_invalid_json()` + +**Purpose:** Test runtime settings rejects invalid JSON. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_post_runtime_settings_updates_engine(mock_transition)` + +**Purpose:** Verify post runtime settings updates engine. + +#### `def RuntimeSettingsApiTests.test_post_runtime_settings_ignores_disabled_engine(mock_transition)` + +**Purpose:** Verify post runtime settings ignores disabled engine. + +#### `def RuntimeSettingsApiTests.test_models_api_returns_engine_specific_models(mock_models)` + +**Purpose:** Verify models api returns engine specific models. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_model_info_api_requires_model_parameter()` + +**Purpose:** Test model info API requires a model query parameter. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_model_info_api_returns_501_for_unimplemented_engines(mock_build_payload)` + +**Purpose:** Verify model info api returns 501 for unimplemented engines. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_inference_info_api_returns_unified_payload(mock_build_payload)` + +**Purpose:** Verify inference info api returns unified payload. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_inference_info_api_uses_runtime_selected_model(mock_build_payload)` + +**Purpose:** Verify inference info api uses runtime selected model. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RuntimeSettingsApiTests.test_runtime_settings_payload_does_not_expose_api_key(_mock_runtime_settings, _mock_engines)` + +**Purpose:** Verify runtime settings payload does not expose api key. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_tools_api_returns_discovered_servers()` + +**Purpose:** Test tools API returns discovered servers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_load_chat_api_returns_active_tool_server_id()` + +**Purpose:** Test load chat API returns active tool server id. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_load_chat_api_returns_multiple_active_tool_server_ids()` + +**Purpose:** Test load chat API returns all active tool server ids. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_load_chat_api_returns_attachment_metadata_without_inline_data()` + +**Purpose:** Test load chat API returns attachment metadata without inline data. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_attachment_content_api_streams_stored_bytes()` + +**Purpose:** Test attachment content API streams stored bytes on demand. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_attachment_content_api_streams_legacy_image_bytes()` + +**Purpose:** Test attachment content API streams legacy image records. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_attachment_content_api_rejects_unknown_record_type()` + +**Purpose:** Test attachment content API rejects unknown record types. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_delete_last_assistant_api_returns_user_message_for_regeneration()` + +**Purpose:** Test delete last assistant API returns the user message to regenerate. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_delete_last_assistant_api_rejects_when_last_message_is_user()` + +**Purpose:** Test delete last assistant API rejects chats ending with a user message. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_delete_message_api_removes_selected_message()` + +**Purpose:** Test delete message API removes only the selected message. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_rename_chat_api_updates_title()` + +**Purpose:** Test rename chat API trims and persists the title. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ToolApiTests.test_delete_chat_api_removes_thread_and_messages()` + +**Purpose:** Test delete chat API removes the whole thread. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.test_model_info_includes_active_ollama_preset_defaults_and_servers(mock_get_model_settings)` + +**Purpose:** Verify model info includes active ollama preset defaults and servers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.test_sync_endpoint_clones_default_preset_on_first_change()` + +**Purpose:** Test sync endpoint clones default preset on first change. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.test_create_rename_delete_endpoints_manage_custom_preset()` + +**Purpose:** Test create rename delete endpoints manage custom preset. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.test_duplicate_preset_name_returns_validation_error()` + +**Purpose:** Test duplicate preset name returns validation error. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.test_select_endpoint_activates_custom_preset()` + +**Purpose:** Test select endpoint activates an existing custom preset. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def OllamaPresetApiTests.test_default_preset_mutation_errors_return_400()` + +**Purpose:** Test default preset mutation errors are returned as validation responses. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.test_model_info_includes_active_lms_preset_defaults(mock_preset_settings, mock_model_settings)` + +**Purpose:** Verify model info includes active lms preset defaults. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.test_sync_endpoint_clones_default_lms_preset_on_first_change(mock_get_model_settings)` + +**Purpose:** Verify sync endpoint clones default lms preset on first change. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.test_get_lms_presets_requires_model()` + +**Purpose:** Test get LM Studio presets endpoint requires a model. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.test_create_rename_delete_endpoints_manage_custom_lms_preset(mock_get_model_settings)` + +**Purpose:** Verify create rename delete endpoints manage custom lms preset. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.test_duplicate_lms_preset_name_returns_validation_error(mock_get_model_settings)` + +**Purpose:** Verify duplicate lms preset name returns validation error. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.test_select_endpoint_activates_custom_lms_preset(mock_get_model_settings)` + +**Purpose:** Verify select endpoint activates custom lms preset. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LmsPresetApiTests.test_default_lms_preset_mutation_errors_return_400(mock_get_model_settings)` + +**Purpose:** Verify default lms preset mutation errors return 400. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageIdAndRegenerateTests.test_chat_api_returns_message_id_headers(_mock_engine, mock_generate, _mock_runtime)` + +**Purpose:** Verify chat api returns message id headers. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageIdAndRegenerateTests.test_regenerate_does_not_duplicate_user_message(_mock_engine, mock_generate, _mock_runtime)` + +**Purpose:** Verify regenerate does not duplicate user message. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def MessageIdAndRegenerateTests.test_chat_updated_at_is_bumped_after_generation(_mock_engine, mock_generate, _mock_runtime)` + +**Purpose:** Verify chat updated at is bumped after generation. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/upload_storage.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/upload_storage.md new file mode 100644 index 0000000..e1a0ab4 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/upload_storage.md @@ -0,0 +1,246 @@ +--- +title: "upload_storage" +draft: false +--- + +## Module `upload_storage` + +`Apps/UI/upload_storage.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Classes + +### `class UploadStorageTarget` + +**Purpose:** Type `UploadStorageTarget` defined in `upload_storage.py`. + +--- + +## Public functions + +#### `def normalize_tool_server_ids(tool_server_ids) -> list[str]` + +**Purpose:** Return a stable list of tool server ids from request payloads. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def resolve_upload_storage_target(tool_server_ids=…) -> UploadStorageTarget` + +**Purpose:** Route UI uploads to the local module upload tree. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def display_kind_for_upload(name, mime) -> tuple[str, str]` + +**Purpose:** Return UI-facing kind and label for one upload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def public_upload_payload(manifest, *, status=…) -> dict[str, Any]` + +**Purpose:** Return the small user-facing upload payload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def model_upload_payload(manifest, *, sandbox_enabled=…) -> dict[str, Any]` + +**Purpose:** Return a model-facing manifest that respects the selected sandbox state. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def resolve_uploaded_file_host_path(manifest) -> Path` + +**Purpose:** Map a stored manifest back to a host file path. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def save_upload_to_sandbox(uploaded_file, *, scope=…, model_supports_vision=…, tool_server_ids=…) -> tuple[UploadedFileManifest, dict[str, Any]]` + +**Purpose:** Persist one Django uploaded file and return its private manifest plus public payload. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def load_upload_manifest(file_id) -> dict[str, Any] | None` + +**Purpose:** Load a private manifest by file id from external storage or legacy sidecars. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +--- + +## Private functions + +#### `def _safe_scope(value) -> str` + +**Purpose:** Safe scope. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _stored_file_name(file_id, original_name) -> str` + +**Purpose:** Stored file name. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _manifest_sidecar_path(file_path) -> Path` + +**Purpose:** Manifest sidecar path. + +#### `def _manifest_storage_dir(sha256) -> Path` + +**Purpose:** Manifest storage dir. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _manifest_storage_path(manifest) -> Path` + +**Purpose:** Manifest storage path. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _write_manifest(manifest) -> None` + +**Purpose:** Write manifest. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def _model_sandbox_path(model_prefix, scope, stored_name) -> str` + +**Purpose:** Model sandbox path. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _file_sha256(file_bytes) -> str` + +**Purpose:** File sha256. + +#### `def _format_upload_size(size_bytes) -> str` + +**Purpose:** Format upload size. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _stream_upload_to_temp(uploaded_file, *, incoming_root) -> tuple[Path, int, str, bytes | None]` + +**Purpose:** Stream upload to temp. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. + +#### `def _load_manifest_from_sidecar(sidecar_path) -> dict[str, Any] | None` + +**Purpose:** Load manifest from sidecar. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _iter_manifest_paths_for_sha(sha256)` + +**Purpose:** Iterate manifest paths for sha. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _find_stored_manifest(*, sha256, size_bytes, clean_name, sandbox_path=…) -> dict[str, Any] | None` + +**Purpose:** Find stored manifest. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _find_existing_upload(target_dir, *, model_prefix, safe_scope, clean_name, file_bytes) -> tuple[Path, dict[str, Any] | None] | None` + +**Purpose:** Find existing upload. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _find_existing_upload_by_hash(target_dir, *, sha256, size_bytes, clean_name) -> tuple[Path, dict[str, Any] | None] | None` + +**Purpose:** Find existing upload by hash. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _manifest_from_dict(manifest) -> UploadedFileManifest | None` + +**Purpose:** Manifest from dict. + +#### `def _normalize_existing_manifest_for_path(manifest, *, model_prefix, safe_scope, stored_name) -> UploadedFileManifest | None` + +**Purpose:** Normalize existing manifest for path. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_lightweight_upload_manifest(*, file_id, clean_name, mime, size_bytes, sha256, sandbox_path, model_supports_vision, tool_server_id=…) -> UploadedFileManifest` + +**Purpose:** Build lightweight upload manifest. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/urls.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/urls.md new file mode 100644 index 0000000..c63b527 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/urls.md @@ -0,0 +1,20 @@ +--- +title: "urls" +draft: false +--- + +## Module `urls` + +`Apps/UI/urls.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/views.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/views.md new file mode 100644 index 0000000..0d19214 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/UI/views.md @@ -0,0 +1,1849 @@ +--- +title: "views" +draft: false +--- + +## Module `views` + +`Apps/UI/views.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Apps\UI`. See **Related** for package index and callers. + +--- + +## Classes + +### `class RequestEngineResolutionError` + +**Purpose:** The requested engine is not enabled in settings. + +### `class PreparedGenerationRequest` + +**Purpose:** Type `PreparedGenerationRequest` defined in `views.py`. + +### `class MainView` + +**Purpose:** Type `MainView` defined in `views.py`. + +### `class WorkspaceMainView` + +**Purpose:** Type `WorkspaceMainView` defined in `views.py`. + +### `class WorkspaceChatView` + +**Purpose:** Type `WorkspaceChatView` defined in `views.py`. + +--- + +## Public functions + +#### `def MainView.get_context_data(**kwargs) -> dict[str, Any]` + +**Purpose:** Build the main page context. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def WorkspaceMainView.get_context_data(**kwargs) -> dict[str, Any]` + +**Purpose:** Build the workspace page context. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def upload_files_api(request)` + +**Purpose:** Store uploaded files and return UI-facing file cards. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. +4. Parse or serialize JSON payloads. + +#### `def chat_api(request)` + +**Purpose:** Handle a chat generation request. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def uploaded_file_content_api(request, file_id)` + +**Purpose:** Return uploaded file bytes on demand. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def shared_file_download_api(request)` + +**Purpose:** Download a model-shared local file after validating its workspace path. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def abort_generation_api(request)` + +**Purpose:** Abort active generation. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def attachment_content_api(request, record_type, attachment_id)` + +**Purpose:** Return stored attachment bytes on demand. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def delete_message_api(request, message_id)` + +**Purpose:** Delete a specific message by ID. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def delete_last_assistant_api(request, chat_id)` + +**Purpose:** Delete the last assistant reply for regeneration. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def regenerate_chat_api(request, chat_id)` + +**Purpose:** Regenerate the assistant reply for an existing user message without duplicating it. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def rename_chat_api(request, chat_id)` + +**Purpose:** Rename a chat thread. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def delete_chat_api(request, chat_id)` + +**Purpose:** Delete a chat thread and all its messages. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def load_chat_api(request, chat_id)` + +**Purpose:** Load persisted messages for a chat thread. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def get_model_info_api(request)` + +**Purpose:** Return model metadata for the selected engine. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def get_inference_info_api(request)` + +**Purpose:** Return unified runtime inference metadata for the active engine/model. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def get_models_api(request)` + +**Purpose:** Return the model list for the selected engine. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def mcp_config_api(request)` + +**Purpose:** Return discovered tool servers. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def skills_api(request)` + +**Purpose:** List skills or create a new skill folder. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def skills_folder_api(request)` + +**Purpose:** Rename or delete one skill folder. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def skills_file_api(request)` + +**Purpose:** Read, write, or delete one skill file. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def skills_enabled_api(request)` + +**Purpose:** Enable or disable one skill. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def skills_directory_api(request)` + +**Purpose:** Create or delete a subdirectory inside a skill folder. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def skills_import_api(request)` + +**Purpose:** Import a skill folder from a list of {path, content} file entries. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def skills_path_api(request)` + +**Purpose:** Rename a file or directory inside a skill folder. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def get_tools_api(request)` + +**Purpose:** Return locally discovered MCP-style tool servers for the requested engine/model. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def favicon_api(request)` + +**Purpose:** Resolve and proxy a stable favicon for a search result domain. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_ollama_presets_api(request)` + +**Purpose:** Return Ollama preset metadata. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def get_context_usage_api(request)` + +**Purpose:** Return estimated/observed context usage for the current chat and model. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def context_compress_api(request)` + +**Purpose:** Force or opportunistically run context compression and persist a timeline marker. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def get_lms_presets_api(request)` + +**Purpose:** Return preset metadata for the selected LM Studio model. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def sync_ollama_preset_api(request)` + +**Purpose:** Sync the active Ollama preset. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def sync_lms_preset_api(request)` + +**Purpose:** Persist UI changes to the active LM Studio preset. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def select_ollama_preset_api(request)` + +**Purpose:** Activate an Ollama preset. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def select_lms_preset_api(request)` + +**Purpose:** Set the active preset for an LM Studio model. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def create_ollama_preset_api(request)` + +**Purpose:** Create an Ollama preset. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def create_lms_preset_api(request)` + +**Purpose:** Create a new LM Studio preset for the selected model. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def rename_ollama_preset_api(request)` + +**Purpose:** Rename an Ollama preset. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def rename_lms_preset_api(request)` + +**Purpose:** Rename an existing custom LM Studio preset. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def delete_ollama_preset_api(request)` + +**Purpose:** Delete an Ollama preset. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def delete_lms_preset_api(request)` + +**Purpose:** Delete an existing custom preset and fall back to the default one. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def chat_backend_ensure_api(request)` + +**Purpose:** Ensure ASLM-Chat is running and return connectivity status. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def chat_backend_status_api(request)` + +**Purpose:** Return ASLM-Chat backend connectivity for the UI health indicator. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def runtime_settings_api(request)` + +**Purpose:** Read or update runtime settings. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def browser_portal_frame_api(request)` + +**Purpose:** Return the latest frame published by browser_wait_for_user. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def browser_portal_event_api(request)` + +**Purpose:** Queue one human portal event for the active browser_wait_for_user loop. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def WorkspaceChatView.get_context_data(**kwargs) -> dict[str, Any]` + +**Purpose:** Build the preloaded chat page context. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def list_workspaces_api(request)` + +**Purpose:** List registered workspaces. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def create_workspace_api(request)` + +**Purpose:** Create a workspace after the backend opens a native folder picker. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def rename_workspace_api(request, workspace_id)` + +**Purpose:** Rename one workspace. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def delete_workspace_api(request, workspace_id)` + +**Purpose:** Delete one workspace and its chats. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +--- + +## Private functions + +#### `def _read_default_system_prompt() -> str` + +**Purpose:** Read the project-level system prompt file. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _build_runtime_context() -> str` + +**Purpose:** Build dynamic runtime context injected into every system prompt. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_favicon_domain(value) -> str` + +**Purpose:** Normalize one domain string for favicon lookup. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _is_public_favicon_host(host) -> bool` + +**Purpose:** Return whether the host resolves to a public address. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _favicon_url_is_safe(url) -> bool` + +**Purpose:** Return whether one favicon URL is safe to fetch. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _favicon_content_type(response, content) -> str` + +**Purpose:** Infer the favicon MIME type from headers and bytes. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _favicon_safe_get(session, url, *, stream=…) -> Any | None` + +**Purpose:** Perform one bounded HTTP GET with redirect validation. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _fetch_favicon_candidate(session, url) -> tuple[str, bytes] | None` + +**Purpose:** Download one favicon candidate when it is within size limits. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _score_favicon_candidate(candidate) -> int` + +**Purpose:** Rank one favicon candidate by rel, size, and format. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _collect_favicon_candidates(session, base_url) -> list[dict[str, str]]` + +**Purpose:** Collect favicon candidates from HTML, manifests, and fallbacks. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _resolve_favicon_content(domain) -> tuple[str, bytes] | None` + +**Purpose:** Resolve the best favicon bytes for one domain. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _favicon_cache_paths(domain) -> tuple[Path, Path]` + +**Purpose:** Return on-disk cache paths for one favicon domain. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _read_favicon_disk_cache(domain, now) -> tuple[str, bytes] | None` + +**Purpose:** Read a cached favicon when the entry is still valid. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _write_favicon_disk_cache(domain, content_type, content, expires_at) -> None` + +**Purpose:** Persist one favicon payload to the disk cache. + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Parse or serialize JSON payloads. + +#### `def _chat_is_first_user_turn(chat) -> bool` + +**Purpose:** Return whether the chat has not yet persisted a user message. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _compose_system_prompt(user_system_prompt, *, consume_skill_notifications=…, include_skills_baseline=…) -> str` + +**Purpose:** Merge the project prompt with per-request user instructions. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _engine_metadata_scope(engine) -> tuple[str, str]` + +**Purpose:** Return a stable runtime scope for model metadata caches. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _clone_metadata_payload(payload) -> Any` + +**Purpose:** Return a defensive deep copy of a cacheable payload. + +#### `def _clear_model_metadata_caches() -> None` + +**Purpose:** Clear cached model metadata. + +#### `def _clear_tool_server_cache() -> None` + +**Purpose:** Drop cached tool server lists only (e.g. after ``mcp.json`` changes). + +#### `def _remember_active_model(engine, model_name) -> None` + +**Purpose:** Remember the latest selected model for one engine. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _get_remembered_active_model(engine) -> str` + +**Purpose:** Read the latest selected model for one engine. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _coerce_positive_int(value) -> int | None` + +**Purpose:** Convert one value into a positive integer when possible. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _first_positive_int(mapping, keys) -> int | None` + +**Purpose:** Read the first positive integer from a mapping. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _resolve_inference_model(engine, requested_model=…) -> tuple[str, str]` + +**Purpose:** Resolve the model name represented by an inference-info request. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _get_cached_model_info(engine, model_name) -> dict[str, Any] | None` + +**Purpose:** Return cached model info when it is still fresh. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _set_cached_model_info(engine, model_name, payload) -> dict[str, Any]` + +**Purpose:** Store model info in the runtime cache. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _get_cached_model_list(engine) -> list[str] | None` + +**Purpose:** Return cached model names when still fresh. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _set_cached_model_list(engine, models) -> list[str]` + +**Purpose:** Store model names in the runtime cache. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _list_tool_servers_cached(engine, model_name=…) -> list[dict[str, Any]]` + +**Purpose:** Return cached tool servers when still fresh. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _print_runtime_event(message) -> None` + +**Purpose:** Emit one concise runtime event for the ASLM console. + +#### `def _is_expected_runtime_error(exc) -> bool` + +**Purpose:** Return whether the exception is an expected runtime/connectivity failure. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _format_runtime_error(engine, exc) -> str` + +**Purpose:** Return a user-facing runtime error string without noisy transport details. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _strip_llm_control_tokens(content) -> str` + +**Purpose:** Remove assistant-control tokens that should never be shown to the user. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _summarize_option_keys(options, max_keys=…) -> str` + +**Purpose:** Return a short, readable summary of option keys. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _count_request_images(messages) -> int` + +**Purpose:** Count image attachments present in the current outbound request. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _decode_base64_payload(raw_value) -> bytes` + +**Purpose:** Return decoded bytes for one base64 payload or data URL. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _estimate_base64_payload_size(raw_value) -> int` + +**Purpose:** Estimate decoded byte size without materializing the full payload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _is_valid_base64_payload(raw_value) -> bool` + +**Purpose:** Return whether one payload is structurally valid base64. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _parse_data_url(raw_value) -> tuple[str, str]` + +**Purpose:** Split a data URL into MIME type and base64 payload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _guess_attachment_kind(mime_type, name=…) -> str` + +**Purpose:** Return the normalized attachment kind for the payload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_attachment_payload(raw_attachment, order) -> dict[str, Any] | None` + +**Purpose:** Normalize one incoming attachment payload into the storage shape. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_request_attachments(data) -> list[dict[str, Any]]` + +**Purpose:** Return a normalized list of request attachments. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _attachment_content_url(record_type, record_id) -> str` + +**Purpose:** Build an attachment content endpoint path. + +#### `def _serialize_attachment_record(attachment, *, include_data=…) -> dict[str, Any]` + +**Purpose:** Convert a persisted attachment-like object into the frontend payload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _get_message_attachments(message, *, include_data=…) -> list[dict[str, Any]]` + +**Purpose:** Return all persisted attachments for a message in a shared shape. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _attachment_data_to_bytes(attachment) -> bytes` + +**Purpose:** Decode one serialized attachment payload into bytes. + +#### `def _is_text_attachment(mime_type, name) -> bool` + +**Purpose:** Return whether the attachment should be decoded as text. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _truncate_attachment_text(text, limit=…) -> str` + +**Purpose:** Trim attachment text so prompts stay bounded. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _cache_attachment_text(attachment, extracted_text) -> str` + +**Purpose:** Persist extracted text for one stored file attachment. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _extract_attachment_text(attachment) -> str` + +**Purpose:** Extract prompt-friendly text from a file attachment when possible. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _build_file_attachment_prompt_block(attachment) -> str` + +**Purpose:** Serialize one non-image attachment into universal text context. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _selected_tools_include_sandbox(selected_tool_servers) -> bool` + +**Purpose:** Return whether the resolved tool selection includes sandbox file access. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_uploaded_file_ids(data) -> list[str]` + +**Purpose:** Return uploaded file ids referenced by a chat request. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _load_model_upload_manifests(file_ids, *, sandbox_enabled) -> list[dict[str, Any]]` + +**Purpose:** Load model-facing upload manifests for the selected tool state. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _upload_manifest_file_ids(manifests) -> list[str]` + +**Purpose:** Return stable file ids from loaded upload manifests. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_uploaded_file_context_entry(file_ids) -> dict[str, Any] | None` + +**Purpose:** Build a stored user-message entry that keeps upload context replayable. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _extract_uploaded_file_ids_from_message(message) -> list[str]` + +**Purpose:** Return upload ids persisted on a user message. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _load_message_upload_manifests(message, *, sandbox_enabled) -> list[dict[str, Any]]` + +**Purpose:** Load persisted upload manifests for one stored user message. + +#### `def _build_uploaded_file_prompt_block(manifest) -> str` + +**Purpose:** Serialize one uploaded file manifest into private model context. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _apply_uploaded_file_manifests_to_llm_entry(entry, manifests) -> dict[str, Any]` + +**Purpose:** Attach uploaded file manifests to the current user entry. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _apply_attachments_to_llm_entry(entry, attachments) -> dict[str, Any]` + +**Purpose:** Attach images and file context to one outbound LLM message. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _get_local_gpu_devices() -> list[dict[str, Any]]` + +**Purpose:** Read local GPU devices + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. +4. Spawn or communicate with a child process. + +#### `def _get_active_facade_engine(requested_engine=…) -> str` + +**Purpose:** Resolve the default active facade engine without request context. + +#### `def _get_active_backend_engine(requested_facade_engine=…) -> str` + +**Purpose:** Resolve the backend engine used for ASLM-Chat proxy calls. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _get_active_engine(requested_engine=…) -> str` + +**Purpose:** Backward-compatible alias. + +#### `def _resolve_request_engine(request, data=…) -> str` + +**Purpose:** Resolve one backend engine from an HTTP request body and/or query string. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _resolve_request_engine_or_response(request, data=…)` + +**Purpose:** Resolve one request engine or return a JSON error response. + +#### `def _extract_model_name(model_entry) -> str` + +**Purpose:** Extract model name + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _load_models_for_engine(engine) -> tuple[list[str], str | None]` + +**Purpose:** Load engine models + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _serialize_workspace(workspace) -> dict[str, Any]` + +**Purpose:** Serialize one workspace for templates and JSON APIs. + +#### `def _get_workspace(workspace_id) -> Workspace` + +**Purpose:** Load one workspace or raise LookupError. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def _workspace_allowed_roots() -> list[Path]` + +**Purpose:** Return registered workspace directories used for shared file access. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _build_workspace_chat_groups() -> list[dict[str, Any]]` + +**Purpose:** Build sidebar groups of chats keyed by workspace. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_base_context(*, workspace_id=…) -> dict[str, Any]` + +**Purpose:** Build shared template context + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _build_runtime_settings_payload() -> dict[str, Any]` + +**Purpose:** Build runtime settings payload + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _build_chat_title(message, has_attachments) -> str` + +**Purpose:** Build chat title + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _detect_image_mime(base64_data) -> str` + +**Purpose:** Detect image MIME type + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _strip_llm_markup(content) -> str` + +**Purpose:** Strip legacy markup + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_transcript_entries(raw_entries) -> list[dict[str, Any]]` + +**Purpose:** Normalize transcript entries + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _llm_entries_from_assistant_transcript(transcript_entries, *, content_fallback=…) -> list[dict[str, Any]]` + +**Purpose:** Convert one assistant transcript into LLM history entries. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _normalize_attachments_from_mapping(data) -> list[dict[str, Any]]` + +**Purpose:** Normalize inline attachments from one request mapping. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_llm_entries_from_request_message(message, *, sandbox_enabled=…) -> list[dict[str, Any]]` + +**Purpose:** Build LLM history entries from one request-side history message. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_llm_history_entries(message, *, sandbox_enabled=…) -> list[dict[str, Any]]` + +**Purpose:** Build LLM history entries + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _message_has_context_compression_summary(message) -> bool` + +**Purpose:** Return whether one stored assistant message represents a compression marker. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_context_compression_source_entries(history_records, *, sandbox_enabled=…) -> list[dict[str, Any]]` + +**Purpose:** Build chronological non-compression entries represented by a new boundary. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_activity_segments(message) -> list[dict[str, Any]]` + +**Purpose:** Build activity segments + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _message_has_reasoning_segments(message) -> bool` + +**Purpose:** Return whether the stored transcript contains model reasoning. + +#### `def _serialize_message(message, *, include_attachment_data=…) -> dict[str, Any]` + +**Purpose:** Serialize message + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _extract_stream_message_parts(chunk) -> tuple[str, str]` + +**Purpose:** Extract streamed message parts + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _copy_transcript_entries_for_storage(transcript_entries) -> list[dict[str, Any]]` + +**Purpose:** Return transcript entries safe to persist while a response is streaming. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_streaming_assistant_transcript(transcript_entries, *, visible_content, thinking_content) -> list[dict[str, Any]]` + +**Purpose:** Overlay streamed assistant text onto machine transcript entries. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _serialize_tool_call_marker(tool_event) -> str` + +**Purpose:** Serialize tool marker + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _serialize_tool_result_marker(alias, content, *, tool_ui=…, structured_content=…) -> str` + +**Purpose:** Serialize tool result marker + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _serialize_context_compression_marker(compression_event) -> str` + +**Purpose:** Encode a context-compression boundary without pretending it is a model tool. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _normalize_capability_tokens(capabilities) -> set[str]` + +**Purpose:** Extract Ollama model info + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _ollama_template_supports_tool_calling(template) -> bool` + +**Purpose:** Return whether one Ollama chat template can serialize tools. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _ollama_metadata_supports_tool_calling(capabilities, template) -> bool` + +**Purpose:** Return whether Ollama metadata is strong enough to expose local tools. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _extract_ollama_model_info(settings_data) -> dict[str, Any]` + +**Purpose:** Parse Ollama-specific model metadata into a frontend-friendly payload. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _extract_generic_model_info(settings_data) -> dict[str, Any]` + +**Purpose:** Extract generic model info + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_fallback_model_info_payload(engine, model_name) -> dict[str, Any]` + +**Purpose:** Build model info payload + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_model_info_payload(engine, model_name, *, allow_fallback=…) -> dict[str, Any]` + +**Purpose:** Load adapter metadata and normalize it for the frontend. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. + +#### `def _get_engine_label(engine) -> str` + +**Purpose:** Build a stable engine label for API payloads. + +#### `def _build_inference_info_payload(engine, model_name, model_info_payload, model_source) -> dict[str, Any]` + +**Purpose:** Normalize model metadata into a compact runtime-inference payload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _runtime_metadata_source(name, route, port_setting) -> dict[str, Any]` + +**Purpose:** Describe one local metadata source without freezing dynamic ports. + +#### `def _read_runtime_metadata_file() -> dict[str, Any]` + +**Purpose:** Return runtime metadata file. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _write_runtime_metadata_file(payload) -> None` + +**Purpose:** Write runtime metadata file. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def _sync_runtime_model_metadata(engine, model_name, model_info_payload, *, source, route) -> None` + +**Purpose:** Persist active model metadata for local tools in real time. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `def _read_json_request_body(request) -> dict[str, Any]` + +**Purpose:** Read JSON body + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Parse or serialize JSON payloads. + +#### `def _resolve_tool_servers(engine, model_name, tool_server_ids) -> list[dict[str, Any]]` + +**Purpose:** Resolve selected tool servers from the local Code registry and optional Chat ids. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _validate_tool_server_support(engine, model_name, tool_server_ids, payload=…) -> None` + +**Purpose:** Raise when tools are requested for a model that should not call tools. + +**Steps:** + +1. Raise on invalid input or failure conditions. + +#### `def _parse_active_tool_slugs(slug) -> list[str]` + +**Purpose:** Parse stored tool slugs + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _resolve_chat(chat_id, workspace_id, user_message, attachments) -> Chat` + +**Purpose:** Resolve chat instance + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def _store_message_attachments(message_record, attachments) -> None` + +**Purpose:** Save message images + +#### `def _resolve_history_char_budget(model_info_payload, *, active_engine=…, active_model=…, observed_chars_per_token=…) -> int` + +**Purpose:** Resolve a bounded history budget from model metadata. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _estimate_llm_entry_chars(entry) -> int` + +**Purpose:** Estimate the prompt cost of one normalized LLM entry. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _estimate_tokens_from_chars(char_count) -> int` + +**Purpose:** Approximate token count from UTF-8 character count. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _model_chars_per_token_hint(*, model_info_payload, active_engine, active_model) -> float` + +**Purpose:** Return one base chars/token hint from model family and engine metadata. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _effective_chars_per_token_hint(*, model_info_payload, active_engine, active_model, observed_chars_per_token=…) -> float` + +**Purpose:** Return the chars/token ratio shared by usage telemetry and compression. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _history_char_budget_from_context_window(context_window_tokens, *, model_info_payload, active_engine, active_model, observed_chars_per_token=…, minimum_chars=…, fallback_chars=…) -> int` + +**Purpose:** Convert a token context window into the same char budget the UI estimates. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _estimate_tokens_adaptive(*, char_count, model_info_payload, active_engine, active_model, observed_chars_per_token=…) -> int` + +**Purpose:** Estimate tokens using model hints + optional observed prompt telemetry. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _context_window_tokens_from_model_info(model_info_payload) -> int` + +**Purpose:** Context window tokens from model info. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _resolve_runtime_context_tokens(model_info_payload, *, debug_force_4k=…) -> int` + +**Purpose:** Resolve context window size from model metadata supplied by ASLM-Chat. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _chat_decide_compression(*, engine, model_name, model_info_payload, used_history_chars, history_budget_chars) -> dict[str, Any]` + +**Purpose:** Ask ASLM-Chat whether history compression should run. + +#### `def _chat_build_compression_event(*, engine, model_name, model_info_payload, force, used_history_chars, history_budget_chars, overflow_entries, summary_source_entries, recent_user_messages, direct_user_directives, compression_mode=…, summarize_with_model=…) -> dict[str, Any] | None` + +**Purpose:** Build one compression timeline event via ASLM-Chat. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _estimate_context_usage(*, chat, system_prompt, draft_text, model_info_payload, active_engine=…, active_model=…) -> dict[str, Any]` + +**Purpose:** Estimate current context usage for UI telemetry. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_manual_compression_event(*, chat, system_prompt, engine, model_name, model_info_payload, force, draft_text=…, exclude_message_ids=…, summarize_with_model_enabled=…) -> dict[str, Any] | None` + +**Purpose:** Build one compression event payload for manual/auto UI-triggered compression. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _collect_recent_user_messages(chat, exclude_message_id) -> list[str]` + +**Purpose:** Collect recent user messages. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _collect_direct_user_directives(chat, exclude_message_id) -> list[str]` + +**Purpose:** Collect direct user directives. + +#### `def _build_chat_history(chat, user_message_record, user_message, system_prompt, engine, model_name, model_info_payload=…, upload_manifests=…, sandbox_enabled=…) -> tuple[list[dict[str, Any]], dict[str, Any] | None]` + +**Purpose:** Build LLM message history + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _split_generation_options(options, think_param_name=…, think_level_param_name=…) -> tuple[Any, Any, dict[str, Any]]` + +**Purpose:** Split generation options + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_lms_sync_operation_defaults(engine, model_info_payload, think_value, think_level_value) -> dict[str, Any] | None` + +**Purpose:** Build LMS sync defaults for one generation request. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _prepare_generation_request(request, data, *, route, require_user_input=…, user_message=…, attachments=…, uploaded_file_ids=…) -> PreparedGenerationRequest | JsonResponse` + +**Purpose:** Validate and normalize one shared generation request payload. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _resolve_include_skills_baseline(data, history_messages) -> bool` + +**Purpose:** Resolve whether the skills inventory should be injected into the system prompt. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_request_history_messages(raw_messages) -> list[dict[str, Any]]` + +**Purpose:** Normalize request-side conversation history. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _request_message_has_context_compression_summary(message) -> bool` + +**Purpose:** Return whether one request history message stores a compression boundary. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _collect_recent_user_messages_from_history(history_messages, current_user_text) -> list[str]` + +**Purpose:** Collect recent user messages from request-side history. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _build_context_compression_source_entries_from_request(history_records_newest_first, *, sandbox_enabled=…) -> list[dict[str, Any]]` + +**Purpose:** Build chronological compression source entries from request history. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _split_request_conversation(data, history_messages) -> tuple[list[dict[str, Any]], str, list[dict[str, Any]], list[str]]` + +**Purpose:** Split request history and the current user turn. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_current_user_llm_entry(user_message, attachments, upload_manifests) -> dict[str, Any]` + +**Purpose:** Build the current user LLM entry for stateless generation. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_generate_llm_messages(history_messages, current_entry, system_prompt, engine, model_name, model_info_payload, *, session_id, sandbox_enabled=…) -> tuple[list[dict[str, Any]], dict[str, Any] | None]` + +**Purpose:** Build LLM messages for stateless generation from request payload. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _inject_ephemeral_system_notice(llm_messages, notice) -> None` + +**Purpose:** Insert a one-off system notice after the main system prompt, without persisting a message. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _build_generate_kwargs(engine, model_name, llm_messages, think_value, think_level_value, clean_options, session_id, selected_tool_servers, think_param_name=…, think_level_param_name=…, sync_operation_defaults=…) -> dict[str, Any]` + +**Purpose:** Build generation kwargs + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _stream_chat_response(engine, generate_kwargs, generation_id, *, chat=…, assistant_message_record=…, session_id=…, compression_event=…, model_info_payload=…, system_prompt=…, current_user_message_id=…, persist_messages=…)` + +**Purpose:** Stream and save assistant response + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. +4. Parse or serialize JSON payloads. + +#### `def _apply_streaming_response_headers(response) -> StreamingHttpResponse` + +**Purpose:** Disable intermediary buffering for live chat token streaming. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _path_is_within(path, root) -> bool` + +**Purpose:** Message and chat management APIs. + +#### `def _shared_file_allowed_roots() -> list[Path]` + +**Purpose:** Shared file allowed roots. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _resolve_shared_file_path(raw_path) -> Path` + +**Purpose:** Resolve shared file path. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. + +#### `def _resolve_uploaded_file_content_path(manifest) -> Path` + +**Purpose:** Return the local path for one uploaded file manifest. + +#### `def _range_not_satisfiable_response(file_size) -> HttpResponse` + +**Purpose:** Range not satisfiable response. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _parse_single_byte_range(range_header, file_size) -> tuple[int, int] | None` + +**Purpose:** Return one satisfiable byte range, including suffix ranges. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _stream_local_file_response(request, target, *, mime_type, safe_name, disposition=…)` + +**Purpose:** Stream a local file with HTTP Range support for media playback. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _skills_error_response(exc) -> JsonResponse` + +**Purpose:** Return a normalized JSON error for skills APIs. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _preset_mutation_response(payload) -> JsonResponse` + +**Purpose:** Return a JSON response after invalidating model metadata. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _browser_portal_roots() -> list[Path]` + +**Purpose:** Browser portal roots. + +#### `def _browser_portal_debug_log_path(root=…) -> Path` + +**Purpose:** Browser portal debug log path. + +#### `def _browser_portal_debug_safe(value, *, depth=…) -> Any` + +**Purpose:** Browser portal debug safe. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _browser_portal_http_event_body_for_log(data) -> dict[str, Any]` + +**Purpose:** Compact portal POST body for debug.jsonl (typing floods the log otherwise). + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _write_browser_portal_debug_event(root, event, **fields) -> None` + +**Purpose:** Browser portal debug logging is intentionally disabled. + +#### `def _read_browser_portal_state_from(root) -> dict[str, Any] | None` + +**Purpose:** Return browser portal state from. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _is_active_browser_portal_state(payload) -> bool` + +**Purpose:** Is active browser portal state. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _active_browser_portal_root() -> Path | None` + +**Purpose:** Active browser portal root. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _browser_portal_state_path() -> Path` + +**Purpose:** Browser portal state path. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _browser_portal_events_dir() -> Path` + +**Purpose:** Browser portal events dir. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _read_browser_portal_state() -> dict[str, Any]` + +**Purpose:** Return browser portal state. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [UI/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Apps/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Apps/_index.md new file mode 100644 index 0000000..1df7ddf --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Apps/_index.md @@ -0,0 +1,23 @@ +--- +title: "Apps" +draft: false +--- + +## Package `Apps` + +Sources under `Apps/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [Data](Data/) | `Apps/Data/` | Submodules | +| [UI](UI/) | `Apps/UI/` | Submodules | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/_index.md new file mode 100644 index 0000000..3ddd97d --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/_index.md @@ -0,0 +1,27 @@ +--- +title: "Runtime" +draft: false +--- + +## Package `Runtime` + +Sources under `Runtime/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [backends](backends/) | `Runtime/backends/` | Submodules | +| [config](config/) | `Runtime/config/` | Submodules | +| [executors](executors/) | `Runtime/executors/` | Submodules | +| [event_log](event_log/) | `event_log.py` | ASLM Code module | +| [run_manager](run_manager/) | `run_manager.py` | ASLM Code module | +| [types](types/) | `types.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/_index.md new file mode 100644 index 0000000..cab0f38 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/_index.md @@ -0,0 +1,23 @@ +--- +title: "backends" +draft: false +--- + +## Package `backends` + +Sources under `Runtime/backends/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [base](base/) | `base.py` | ASLM Code module | +| [thread_backend](thread_backend/) | `thread_backend.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/base.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/base.md new file mode 100644 index 0000000..644f23e --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/base.md @@ -0,0 +1,40 @@ +--- +title: "base" +draft: false +--- + +## Module `base` + +`Runtime/backends/base.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime\backends`. See **Related** for package index and callers. + +--- + +## Classes + +### `class RunBackend` + +**Purpose:** Type `RunBackend` defined in `base.py`. + +--- + +## Public functions + +#### `def RunBackend.spawn(run_id, spec) -> None` + +**Purpose:** Start executing one run; must return immediately without blocking. + +#### `def RunBackend.abort(run_id) -> bool` + +**Purpose:** Request cooperative cancellation of one run. + +--- + +## Related + +- [backends/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/thread_backend.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/thread_backend.md new file mode 100644 index 0000000..9683ff7 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/backends/thread_backend.md @@ -0,0 +1,77 @@ +--- +title: "thread_backend" +draft: false +--- + +## Module `thread_backend` + +`Runtime/backends/thread_backend.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime\backends`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ThreadRunBackend` + +**Purpose:** Type `ThreadRunBackend` defined in `thread_backend.py`. + +--- + +## Public functions + +#### `def ThreadRunBackend.__init__(event_log, executor, store) -> None` + +**Purpose:** Bind the backend to the shared event log, executor, and status store. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ThreadRunBackend.spawn(run_id, spec) -> None` + +**Purpose:** Start one run on a background thread and return immediately. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ThreadRunBackend.abort(run_id) -> bool` + +**Purpose:** Request cooperative cancellation for one running thread. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def ThreadRunBackend._run(run_id, spec, abort_event) -> None` + +**Purpose:** Execute one run, funneling its output and status into shared state. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def ThreadRunBackend._finish(run_id, status, emit, error=…) -> None` + +**Purpose:** Record the terminal status, emit closing events, and release run state. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Related + +- [backends/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/_index.md new file mode 100644 index 0000000..772a9fa --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/_index.md @@ -0,0 +1,23 @@ +--- +title: "config" +draft: false +--- + +## Package `config` + +Sources under `Runtime/config/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [aggregator](aggregator/) | `aggregator.py` | ASLM Code module | +| [sources](sources/) | `sources.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/aggregator.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/aggregator.md new file mode 100644 index 0000000..2536f69 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/aggregator.md @@ -0,0 +1,106 @@ +--- +title: "aggregator" +draft: false +--- + +## Module `aggregator` + +`Runtime/config/aggregator.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime\config`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ConfigAggregator` + +**Purpose:** Type `ConfigAggregator` defined in `aggregator.py`. + +--- + +## Public functions + +#### `def ConfigAggregator.__init__(settings_source=…, metadata_source=…, core_source=…) -> None` + +**Purpose:** Compose the aggregator from its backing sources. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ConfigAggregator.active_engine() -> str` + +**Purpose:** Return the effective backend engine the user is currently driving. + +#### `def ConfigAggregator.active_model(engine=…) -> str` + +**Purpose:** Return the active model for one engine, defaulting to the current engine. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ConfigAggregator.available_engines() -> list[str]` + +**Purpose:** Return the list of engine ids the user has enabled. + +#### `def ConfigAggregator.model_caps(engine, model) -> dict[str, Any]` + +**Purpose:** Return the capability flags for one engine/model pair. + +#### `def ConfigAggregator.model_limits(engine, model) -> dict[str, Any]` + +**Purpose:** Return the limit values for one engine/model pair. + +#### `def ConfigAggregator.resolve(overrides=…) -> ResolvedConfig` + +**Purpose:** Freeze defaults and overrides into one validated run configuration. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def main() -> None` + +**Purpose:** Print a resolved snapshot of the current active configuration for smoke testing. + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Parse or serialize JSON payloads. + +--- + +## Private functions + +#### `def ConfigAggregator._limits_summary(engine, model) -> LimitsSummary` + +**Purpose:** Build the frozen model-capability summary for one engine/model pair. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ConfigAggregator._engine_config(engine, sub_engine) -> EngineConfig` + +**Purpose:** Build the frozen engine coordinates for one engine. + +#### `def ConfigAggregator._run_limits(overrides) -> RunLimits` + +**Purpose:** Merge built-in limits with the core source and per-run overrides. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [config/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/sources.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/sources.md new file mode 100644 index 0000000..f4c40ca --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/config/sources.md @@ -0,0 +1,149 @@ +--- +title: "sources" +draft: false +--- + +## Module `sources` + +`Runtime/config/sources.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime\config`. See **Related** for package index and callers. + +--- + +## Classes + +### `class SettingsSource` + +**Purpose:** Type `SettingsSource` defined in `sources.py`. + +### `class ModelMetadataSource` + +**Purpose:** Type `ModelMetadataSource` defined in `sources.py`. + +### `class RuntimeCoreSource` + +**Purpose:** Type `RuntimeCoreSource` defined in `sources.py`. + +--- + +## Public functions + +#### `def SettingsSource.active_engine() -> str` + +**Purpose:** Return the effective backend engine the user is currently driving. + +#### `def SettingsSource.facade_engine() -> str` + +**Purpose:** Return the configured facade engine name. + +#### `def SettingsSource.sub_engine() -> str` + +**Purpose:** Return the backend sub-engine resolved behind the facade. + +#### `def SettingsSource.engine_url(engine) -> str` + +**Purpose:** Return the resolved base URL for one engine. + +#### `def SettingsSource.engine_api_key(engine) -> str` + +**Purpose:** Return the resolved API key for one engine. + +#### `def SettingsSource.runtime_engine_settings() -> dict[str, Any]` + +**Purpose:** Return per-engine runtime settings shared with the frontend. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def SettingsSource.enabled_engines() -> list[str]` + +**Purpose:** Return the list of engine ids the user has enabled. + +#### `def ModelMetadataSource.__init__(path=…) -> None` + +**Purpose:** Bind the source to the metadata file and prepare its mtime cache. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ModelMetadataSource.active() -> dict[str, str]` + +**Purpose:** Return the recorded active engine and model selection. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ModelMetadataSource.model_entry(engine, model) -> dict[str, Any]` + +**Purpose:** Return the raw catalog entry for one engine/model pair. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ModelMetadataSource.capabilities(engine, model) -> dict[str, Any]` + +**Purpose:** Return the capability flags recorded for one engine/model pair. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ModelMetadataSource.limits(engine, model) -> dict[str, Any]` + +**Purpose:** Return the limit values recorded for one engine/model pair. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RuntimeCoreSource.__init__(path=…) -> None` + +**Purpose:** Bind the source to the optional override file. + +#### `def RuntimeCoreSource.values() -> dict[str, Any]` + +**Purpose:** Return the merged core settings (defaults overlaid with the override file). + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def RuntimeCoreSource.get(key, default=…) -> Any` + +**Purpose:** Return one core setting value with a fallback default. + +--- + +## Private functions + +#### `def ModelMetadataSource._load() -> dict[str, Any]` + +**Purpose:** Return the parsed metadata document, refreshing only when the file changes. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def ModelMetadataSource._model_key(engine, model) -> str` + +**Purpose:** Build the catalog key used to look up one engine/model pair. + +--- + +## Related + +- [config/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/event_log.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/event_log.md new file mode 100644 index 0000000..d832c35 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/event_log.md @@ -0,0 +1,112 @@ +--- +title: "event_log" +draft: false +--- + +## Module `event_log` + +`Runtime/event_log.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime`. See **Related** for package index and callers. + +--- + +## Classes + +### `class _RunBuffer` + +**Purpose:** Type `_RunBuffer` defined in `event_log.py`. + +### `class EventLog` + +**Purpose:** Type `EventLog` defined in `event_log.py`. + +--- + +## Public functions + +#### `def _RunBuffer.__init__() -> None` + +**Purpose:** Initialize an empty, open event buffer. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def EventLog.__init__() -> None` + +**Purpose:** Initialize the per-run buffer registry. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def EventLog.append(run_id, event_type, payload=…) -> RunEvent` + +**Purpose:** Append one event, assign its sequence number, and wake subscribers. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def EventLog.read(run_id, after_seq=…) -> list[RunEvent]` + +**Purpose:** Return all events recorded after one sequence number. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def EventLog.wait(run_id, after_seq, timeout=…) -> list[RunEvent]` + +**Purpose:** Block until new events arrive after one sequence number or the wait times out. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def EventLog.mark_closed(run_id) -> None` + +**Purpose:** Mark one run as finished so subscribers can stop following it. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def EventLog.is_closed(run_id) -> bool` + +**Purpose:** Return whether one run has been marked finished. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def EventLog.last_seq(run_id) -> int` + +**Purpose:** Return the highest sequence number recorded for one run. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def EventLog.discard(run_id) -> None` + +**Purpose:** Drop the buffer for one run once nobody needs its history. + +--- + +## Private functions + +#### `def EventLog._buffer(run_id) -> _RunBuffer` + +**Purpose:** Return the buffer for one run, creating it on first use. + +--- + +## Related + +- [Runtime/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/_index.md new file mode 100644 index 0000000..f54b66e --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/_index.md @@ -0,0 +1,24 @@ +--- +title: "executors" +draft: false +--- + +## Package `executors` + +Sources under `Runtime/executors/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [aslm_chat_executor](aslm_chat_executor/) | `aslm_chat_executor.py` | ASLM Code module | +| [lms_direct_executor](lms_direct_executor/) | `lms_direct_executor.py` | ASLM Code module | +| [stub_executor](stub_executor/) | `stub_executor.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/aslm_chat_executor.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/aslm_chat_executor.md new file mode 100644 index 0000000..c7e409f --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/aslm_chat_executor.md @@ -0,0 +1,32 @@ +--- +title: "aslm_chat_executor" +draft: false +--- + +## Module `aslm_chat_executor` + +`Runtime/executors/aslm_chat_executor.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime\executors`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def execute_aslm_chat(spec, emit, should_abort) -> None` + +**Purpose:** never imports the large views module. + +**Steps:** + +1. Iterate and transform or accumulate state. + +--- + +## Related + +- [executors/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/lms_direct_executor.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/lms_direct_executor.md new file mode 100644 index 0000000..42a335c --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/lms_direct_executor.md @@ -0,0 +1,67 @@ +--- +title: "lms_direct_executor" +draft: false +--- + +## Module `lms_direct_executor` + +`Runtime/executors/lms_direct_executor.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime\executors`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def list_models(base_url) -> list[str]` + +**Purpose:** Return the list of model ids currently loaded in a local OpenAI-compat provider. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def execute_lms_direct(spec, emit, should_abort) -> None` + +**Purpose:** Emits "token" events as deltas arrive and a final "message" event on completion. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. +4. Parse or serialize JSON payloads. + +--- + +## Private functions + +#### `def _base_http_url(raw) -> str` + +**Purpose:** Normalize one raw engine base_url (may lack scheme) to a full http:// URL. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _parse_sse_line(line) -> dict | None` + +**Purpose:** Parse one SSE "data: ..." line into a dict; return None for control lines or [DONE]. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +--- + +## Related + +- [executors/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/stub_executor.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/stub_executor.md new file mode 100644 index 0000000..1fa11a7 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/executors/stub_executor.md @@ -0,0 +1,32 @@ +--- +title: "stub_executor" +draft: false +--- + +## Module `stub_executor` + +`Runtime/executors/stub_executor.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime\executors`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def execute_stub(spec, emit, should_abort) -> None` + +**Purpose:** on nothing in the web layer. + +**Steps:** + +1. Iterate and transform or accumulate state. + +--- + +## Related + +- [executors/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/run_manager.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/run_manager.md new file mode 100644 index 0000000..aa0bf23 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/run_manager.md @@ -0,0 +1,112 @@ +--- +title: "run_manager" +draft: false +--- + +## Module `run_manager` + +`Runtime/run_manager.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime`. See **Related** for package index and callers. + +--- + +## Classes + +### `class RunStore` + +**Purpose:** Type `RunStore` defined in `run_manager.py`. + +### `class RunManager` + +**Purpose:** Type `RunManager` defined in `run_manager.py`. + +--- + +## Public functions + +#### `def RunStore.__init__() -> None` + +**Purpose:** Initialize the empty run registry. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RunStore.create(run_id, spec) -> RunInfo` + +**Purpose:** Register one new run in the pending state. + +#### `def RunStore.set_status(run_id, status, error=…) -> None` + +**Purpose:** Update the status (and optional error) of one run. + +#### `def RunStore.get(run_id) -> RunInfo | None` + +**Purpose:** Return one run's metadata, or None when it is unknown. + +#### `def RunStore.list(chat_id=…, status=…) -> list[RunInfo]` + +**Purpose:** Return runs matching an optional chat id and status filter. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RunManager.__init__(executor, config=…, event_log=…, store=…, backend=…) -> None` + +**Purpose:** Compose the manager from its config, event log, store, and backend. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def RunManager.start(spec) -> str` + +**Purpose:** Start one run in the background and return its identifier immediately. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RunManager.subscribe(run_id, from_seq=…) -> Iterator[RunEvent]` + +**Purpose:** Yield run events from a sequence offset, then follow the live stream. + +**Steps:** + +1. Iterate and transform or accumulate state. + +#### `def RunManager.get(run_id) -> RunInfo | None` + +**Purpose:** Return one run's metadata with its current last sequence number. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RunManager.list(chat_id=…, status=…) -> list[RunInfo]` + +**Purpose:** Return runs matching an optional chat id and status filter. + +#### `def RunManager.abort(run_id) -> bool` + +**Purpose:** Request cooperative cancellation of one run. + +#### `def get_run_manager() -> RunManager` + +**Purpose:** Return the process-wide run manager, creating it on first use. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [Runtime/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Runtime/types.md b/Docs/ASLM/content/docs/ASLM-Code/Runtime/types.md new file mode 100644 index 0000000..18bf5f6 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Runtime/types.md @@ -0,0 +1,152 @@ +--- +title: "types" +draft: false +--- + +## Module `types` + +`Runtime/types.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Runtime`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ConfigError` + +**Purpose:** Type `ConfigError` defined in `types.py`. + +### `class RunStatus` + +**Purpose:** Type `RunStatus` defined in `types.py`. + +### `class EngineConfig` + +**Purpose:** Type `EngineConfig` defined in `types.py`. + +### `class RunLimits` + +**Purpose:** Type `RunLimits` defined in `types.py`. + +### `class LimitsSummary` + +**Purpose:** Type `LimitsSummary` defined in `types.py`. + +### `class ResolvedConfig` + +**Purpose:** Type `ResolvedConfig` defined in `types.py`. + +### `class RunOverrides` + +**Purpose:** Type `RunOverrides` defined in `types.py`. + +### `class RunSpec` + +**Purpose:** Type `RunSpec` defined in `types.py`. + +### `class RunEvent` + +**Purpose:** Type `RunEvent` defined in `types.py`. + +### `class RunInfo` + +**Purpose:** Type `RunInfo` defined in `types.py`. + +--- + +## Public functions + +#### `def EngineConfig.as_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable representation of the engine config. + +#### `def EngineConfig.from_dict(data) -> EngineConfig` + +**Purpose:** Implements `EngineConfig.from_dict` in `types.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RunLimits.as_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable representation of the run limits. + +#### `def RunLimits.from_dict(data) -> RunLimits` + +**Purpose:** Implements `RunLimits.from_dict` in `types.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def LimitsSummary.as_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable representation of the limits summary. + +#### `def LimitsSummary.from_dict(data) -> LimitsSummary` + +**Purpose:** Implements `LimitsSummary.from_dict` in `types.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ResolvedConfig.as_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable representation of the resolved config. + +#### `def ResolvedConfig.from_dict(data) -> ResolvedConfig` + +**Purpose:** Implements `ResolvedConfig.from_dict` in `types.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RunSpec.as_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable representation of the run spec. + +#### `def RunSpec.from_dict(data) -> RunSpec` + +**Purpose:** Implements `RunSpec.from_dict` in `types.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RunEvent.as_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable representation of the run event. + +#### `def RunEvent.from_dict(data) -> RunEvent` + +**Purpose:** Implements `RunEvent.from_dict` in `types.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def RunInfo.as_dict() -> dict[str, Any]` + +**Purpose:** Return a JSON-serializable representation of the run info. + +#### `def RunInfo.from_dict(data) -> RunInfo` + +**Purpose:** Implements `RunInfo.from_dict` in `types.py`. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [Runtime/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Services/_index.md new file mode 100644 index 0000000..cf1ed27 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/_index.md @@ -0,0 +1,29 @@ +--- +title: "Services" +draft: false +--- + +## Package `Services` + +Sources under `Services/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [aslm_chat_client](aslm_chat_client/) | `aslm_chat_client.py` | ASLM Code module | +| [aslm_chat_resolver](aslm_chat_resolver/) | `aslm_chat_resolver.py` | ASLM Code module | +| [aslm_chat_stream](aslm_chat_stream/) | `aslm_chat_stream.py` | ASLM Code module | +| [aslm_interop_client](aslm_interop_client/) | `aslm_interop_client.py` | ASLM Code module | +| [folder_picker](folder_picker/) | `folder_picker.py` | Native folder picker invoked from the Django backend | +| [tool_worker](tool_worker/) | `tool_worker.py` | ASLM Code module | +| [user_mcp_client](user_mcp_client/) | `user_mcp_client.py` | ASLM Code module | +| [venv_manager](venv_manager/) | `venv_manager.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_client.md b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_client.md new file mode 100644 index 0000000..5a081f2 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_client.md @@ -0,0 +1,263 @@ +--- +title: "aslm_chat_client" +draft: false +--- + +## Module `aslm_chat_client` + +`Services/aslm_chat_client.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ChatRequestError` + +**Purpose:** Raised when ASLM-Chat returns an HTTP or protocol error. + +### `class _ChatHttpSession` + +**Purpose:** Type `_ChatHttpSession` defined in `aslm_chat_client.py`. + +--- + +## Public functions + +#### `def _ChatHttpSession.__init__(base_url) -> None` + +**Purpose:** Implements `_ChatHttpSession.__init__` in `aslm_chat_client.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _ChatHttpSession.ensure_csrf(*, timeout=…) -> str` + +**Purpose:** Prime Django CSRF state with one lightweight GET request. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _ChatHttpSession.post_headers(*, timeout=…) -> dict[str, str]` + +**Purpose:** Build headers required for Django-protected POST requests. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _ChatHttpSession.request_json(method, url, *, body=…, timeout=…) -> tuple[int, dict[str, Any], dict[str, str]]` + +**Purpose:** Perform one HTTP request and return status, parsed JSON, and headers. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _ChatHttpSession.open_stream(url, *, body, timeout=…) -> urllib.response.addinfourl` + +**Purpose:** Open one streaming POST request against ASLM-Chat. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def invalidate_http_session() -> None` + +**Purpose:** Drop cached cookies when ASLM-Chat moves to another host/port. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def get_models(engine) -> list[Any]` + +**Purpose:** Return the model list for one engine from ASLM-Chat. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def get_model_info(engine, model_name) -> dict[str, Any]` + +**Purpose:** Return normalized model metadata from ASLM-Chat. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def get_tool_servers(engine, model_name=…) -> list[dict[str, Any]]` + +**Purpose:** Return tool servers exposed by ASLM-Chat for one engine/model pair. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def abort_generation(*, engine, generation_id=…) -> dict[str, Any]` + +**Purpose:** Ask ASLM-Chat to abort one in-flight generation. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def iter_generate_stream(payload) -> Iterator[str]` + +**Purpose:** Stream plain-text chunks from ASLM-Chat /api/generate/. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. +4. Parse or serialize JSON payloads. + +#### `def generate_sync(payload) -> str` + +**Purpose:** Collect one non-streaming generate response from ASLM-Chat. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def decide_compression(payload) -> dict[str, Any]` + +**Purpose:** Ask ASLM-Chat whether stateless history compression should run. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def build_compression_event(payload) -> dict[str, Any]` + +**Purpose:** Build one compression timeline event via ASLM-Chat. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def get_backend_status(*, ensure=…) -> dict[str, Any]` + +**Purpose:** Return backend status information for the UI health indicator. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def get_chat_sub_engines() -> list[dict[str, str]]` + +**Purpose:** Return sub-engine options enabled inside ASLM-Chat. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. + +--- + +## Private functions + +#### `def _parse_csrf_from_set_cookie(header_value) -> str` + +**Purpose:** Extract csrftoken from one response Set-Cookie header value. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _parse_csrf_from_html(body) -> str` + +**Purpose:** Extract csrftoken from one HTML page body. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _iter_set_cookie_headers(resp) -> list[str]` + +**Purpose:** Collect every Set-Cookie header value from one HTTP response. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _ChatHttpSession._read_cached_csrf_token() -> str` + +**Purpose:** Read a cached or cookie-jar csrftoken value. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _ChatHttpSession._store_csrf_token(token) -> str` + +**Purpose:** Store one CSRF token and mirror it into the cookie jar. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _ChatHttpSession._parse_csrf_from_response(resp, body) -> str` + +**Purpose:** Parse csrftoken from one prefetch response. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _get_session() -> _ChatHttpSession` + +**Purpose:** Return the HTTP session for the currently resolved ASLM-Chat base URL. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _chat_url(path) -> str` + +**Purpose:** Build one absolute URL against the resolved ASLM-Chat base URL. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _request_json(method, path, *, body=…, timeout=…) -> tuple[int, dict[str, Any], dict[str, str]]` + +**Purpose:** Perform one HTTP request against ASLM-Chat and decode JSON responses. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Parse or serialize JSON payloads. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_resolver.md b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_resolver.md new file mode 100644 index 0000000..cd1044b --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_resolver.md @@ -0,0 +1,99 @@ +--- +title: "aslm_chat_resolver" +draft: false +--- + +## Module `aslm_chat_resolver` + +`Services/aslm_chat_resolver.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ChatNotAvailableError` + +**Purpose:** Raised when ASLM-Chat cannot be resolved or reached. + +--- + +## Public functions + +#### `def invalidate_chat_base_url_cache() -> None` + +**Purpose:** Clear the cached ASLM-Chat base URL. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def resolve_chat_base_url(*, force_refresh=…) -> str` + +**Purpose:** Resolve the ASLM-Chat HTTP base URL via the host interop registry. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def ensure_chat_running(*, timeout_seconds=…) -> str` + +**Purpose:** Ask the host to start ASLM-Chat when it is not already running. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. + +#### `def ping_chat_backend(*, base_url=…) -> dict[str, Any]` + +**Purpose:** Perform a lightweight health check against ASLM-Chat. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def is_chat_available() -> bool` + +**Purpose:** Return whether ASLM-Chat appears reachable right now. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +--- + +## Private functions + +#### `def _pick_host_url(host) -> str` + +**Purpose:** Return the direct module HTTP base URL for one running module host entry. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _extract_chat_base_url(registry) -> str` + +**Purpose:** Find the ASLM-Chat base URL inside one interop registry payload. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_stream.md b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_stream.md new file mode 100644 index 0000000..40c7761 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_chat_stream.md @@ -0,0 +1,83 @@ +--- +title: "aslm_chat_stream" +draft: false +--- + +## Module `aslm_chat_stream` + +`Services/aslm_chat_stream.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ChatStreamAccumulator` + +**Purpose:** Accumulate ASLM-Chat plain-text stream chunks for relay persistence. + +--- + +## Public functions + +#### `def strip_stream_markers(text) -> str` + +**Purpose:** Strip control markers from one assistant-visible string. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def parse_completed_stream(text, *, emit_thinking=…) -> tuple[str, str, list[dict[str, Any]]]` + +**Purpose:** Extract visible text, thinking text, and transcript entries from a full stream body. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def ChatStreamAccumulator.__init__(*, emit_thinking=…) -> None` + +**Purpose:** Implements `ChatStreamAccumulator.__init__` in `aslm_chat_stream.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def ChatStreamAccumulator.append(chunk) -> int` + +**Purpose:** Append one streamed chunk and return the updated buffer length. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ChatStreamAccumulator.snapshot() -> tuple[str, str, list[dict[str, Any]]]` + +**Purpose:** Return the latest parsed visible/thinking/transcript snapshot. + +--- + +## Private functions + +#### `def _parse_marker_json(raw) -> dict[str, Any] | None` + +**Purpose:** Parse one tool marker JSON payload safely. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_interop_client.md b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_interop_client.md new file mode 100644 index 0000000..683af6a --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/aslm_interop_client.md @@ -0,0 +1,61 @@ +--- +title: "aslm_interop_client" +draft: false +--- + +## Module `aslm_interop_client` + +`Services/aslm_interop_client.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def get_registry() -> dict[str, Any]` + +**Purpose:** Fetch installed and running modules from GET /v1/registry. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def request_start(*, caller_module_id, module_ids) -> dict[str, Any]` + +**Purpose:** Ask ASLM to start the given module ids via POST /v1/modules/start. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Parse or serialize JSON payloads. + +#### `def is_available() -> bool` + +**Purpose:** Return whether ASLM_MODULE_INTEROP_BASE_URL is set. + +--- + +## Private functions + +#### `def _base_url() -> str` + +**Purpose:** Resolve the ASLM host module interop base URL from the environment. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/folder_picker.md b/Docs/ASLM/content/docs/ASLM-Code/Services/folder_picker.md new file mode 100644 index 0000000..b3aff9c --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/folder_picker.md @@ -0,0 +1,51 @@ +--- +title: "folder_picker" +draft: false +--- + +## Module `folder_picker` + +`Services/folder_picker.py` — Native folder picker invoked from the Django backend. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Classes + +### `class FolderPickerUnavailable` + +**Purpose:** Raised when the native folder picker cannot be opened. + +--- + +## Public functions + +#### `def pick_folder(*, title=…, initial_dir=…) -> str | None` + +**Purpose:** Return an absolute directory path, or None when the user cancels. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def normalize_workspace_path(raw_path) -> str` + +**Purpose:** Normalize a picked folder path for persistence. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/tool_worker.md b/Docs/ASLM/content/docs/ASLM-Code/Services/tool_worker.md new file mode 100644 index 0000000..f75d48f --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/tool_worker.md @@ -0,0 +1,227 @@ +--- +title: "tool_worker" +draft: false +--- + +## Module `tool_worker` + +`Services/tool_worker.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Classes + +### `class AsyncCallableRunner` + +**Purpose:** Type `AsyncCallableRunner` defined in `tool_worker.py`. + +--- + +## Public functions + +#### `def AsyncCallableRunner.__init__() -> None` + +**Purpose:** Implements `AsyncCallableRunner.__init__` in `tool_worker.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AsyncCallableRunner.ensure_started() -> None` + +**Purpose:** Start the background loop thread when it is not already running. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def AsyncCallableRunner.run(coro) -> Any` + +**Purpose:** Execute one coroutine on the background loop and block for the result. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def AsyncCallableRunner.close() -> None` + +**Purpose:** Stop the background loop and join its thread. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def describe(server_file) -> dict[str, Any]` + +**Purpose:** Return public metadata and tool list for one tool server file. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def supports(server_file, payload) -> bool` + +**Purpose:** Return whether the server supports the requested engine and model pair. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def call(server_file, payload) -> Any` + +**Purpose:** Execute one tool call against a server module. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def serve(server_file) -> int` + +**Purpose:** Run a persistent newline-delimited JSON worker on stdin until EOF. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. +4. Parse or serialize JSON payloads. + +#### `def main() -> int` + +**Purpose:** CLI entry point for one-shot and persistent worker modes. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +--- + +## Private functions + +#### `def AsyncCallableRunner._thread_main() -> None` + +**Purpose:** Own the asyncio loop inside a dedicated daemon thread. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `def _slugify(value) -> str` + +**Purpose:** Normalize public identifiers into stable lower-case slugs. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _load_module(server_file) -> ModuleType` + +**Purpose:** Load one tool server module from disk and register its folder on sys.path. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _server_metadata(module, folder_name) -> dict[str, Any]` + +**Purpose:** Read MCP_SERVER (or SERVER) metadata from a loaded module. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def _normalize_schema(schema) -> dict[str, Any]` + +**Purpose:** Normalize one JSON-schema-like tool parameters object. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _server_tools(module, server_id) -> list[dict[str, Any]]` + +**Purpose:** Build normalized tool definitions from a module TOOLS export. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +#### `def _tool_handlers(module) -> dict[str, Any]` + +**Purpose:** Collect explicit per-tool handler callables from the module. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _server_callable(module)` + +**Purpose:** Return the generic tool dispatcher callable when the module exports one. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _execute_callable(callable_fn, *args) -> Any` + +**Purpose:** Invoke sync or async callables, routing coroutines through the shared loop. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _dispatch_server_callable(callable_fn, tool_id, arguments, context) -> Any` + +**Purpose:** Call a generic dispatcher using a tolerant signature-matching strategy. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _to_jsonable(value) -> Any` + +**Purpose:** Convert arbitrary return values into JSON-serializable data. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _print_response(ok, payload, *, output=…) -> int` + +**Purpose:** Print one JSON worker envelope to stdout. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _worker_heartbeat(output=…) -> None` + +**Purpose:** Emit one protocol-safe heartbeat line for the parent process. + +#### `def _execute_request(operation, server_file, payload) -> tuple[bool, Any]` + +**Purpose:** Execute one worker request without printing the envelope. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/user_mcp_client.md b/Docs/ASLM/content/docs/ASLM-Code/Services/user_mcp_client.md new file mode 100644 index 0000000..a622442 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/user_mcp_client.md @@ -0,0 +1,91 @@ +--- +title: "user_mcp_client" +draft: false +--- + +## Module `user_mcp_client` + +`Services/user_mcp_client.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def shutdown_all() -> None` + +**Purpose:** Release per-server locks (reserved for future persistent sessions). + +#### `def fetch_tool_definitions(entry) -> tuple[list[dict[str, Any]], str | None]` + +**Purpose:** Connect once, list tools, and disconnect (serialized per server id). + +**Steps:** + +1. Return the computed result to the caller. + +#### `def call_user_mcp_tool(entry, mcp_tool_name, arguments) -> str` + +**Purpose:** Run one MCP tool call with a new connection per invocation. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Private functions + +#### `def _normalize_parameters_schema(schema) -> dict[str, Any]` + +**Purpose:** Normalize MCP tool input schemas into JSON Schema objects. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _tool_definitions_from_mcp_tools(server_id, mcp_tools) -> tuple[list[dict[str, Any]], str | None]` + +**Purpose:** Convert MCP list_tools results into ASLM tool definition payloads. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _format_call_tool_result(result) -> str` + +**Purpose:** Format one MCP call_tool result as plain text for the chat layer. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. +3. Parse or serialize JSON payloads. + +#### `async def _connect_session(entry)` + +**Purpose:** Implements `_connect_session` in `user_mcp_client.py`. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `async def _list_tools_async(entry) -> tuple[list[dict[str, Any]], str | None]` + +**Purpose:** List tools from one user MCP server over a fresh connection. + +#### `async def _call_tool_async(entry, mcp_tool_name, arguments) -> str` + +**Purpose:** Invoke one MCP tool over a fresh connection. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Services/venv_manager.md b/Docs/ASLM/content/docs/ASLM-Code/Services/venv_manager.md new file mode 100644 index 0000000..3405687 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Services/venv_manager.md @@ -0,0 +1,180 @@ +--- +title: "venv_manager" +draft: false +--- + +## Module `venv_manager` + +`Services/venv_manager.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Services`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def load_config() -> dict[str, Any]` + +**Purpose:** Read venv requirements from Settings/venv_requirements.json. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def iter_venv_configs() -> list[dict[str, Any]]` + +**Purpose:** Return normalized venv definitions from the requirements file. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def get_venv_config(venv_id) -> dict[str, Any] | None` + +**Purpose:** Resolve one venv config by id. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def get_tool_venv_id(tool_dir_name) -> str` + +**Purpose:** Resolve the venv id assigned to a tool directory name. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def get_venv_path(venv_id) -> Path` + +**Purpose:** Return the absolute filesystem path for a configured venv. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def get_venv_python(venv_id) -> Path` + +**Purpose:** Return the Python executable inside a configured venv. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_tool_python(tool_dir_name) -> Path | None` + +**Purpose:** Return the tool venv Python executable when the tool is mapped in config. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ensure_venv(venv_id, *, log=…) -> bool` + +**Purpose:** Create or update one configured ASLM-Chat venv when packages changed. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def ensure_all(*, log=…) -> bool` + +**Purpose:** Create or update every venv listed in the requirements file. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def run_venv_python(venv_id, args, *, log=…) -> bool` + +**Purpose:** Run a Python command inside one configured venv. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def run_venv_code(venv_id, code, *, log=…) -> bool` + +**Purpose:** Run a Python code snippet inside one configured venv. + +--- + +## Private functions + +#### `def _run(command, *, log, cwd=…) -> bool` + +**Purpose:** Run one subprocess command and optionally stream output to the console. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Spawn or communicate with a child process. + +#### `def _packages_signature(packages, packages_no_deps=…) -> str` + +**Purpose:** Compute a stable hash for one venv package manifest. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _read_state(venv_path) -> dict[str, Any]` + +**Purpose:** Read persisted install state for one venv directory. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _write_state(venv_path, packages, packages_no_deps=…) -> None` + +**Purpose:** Persist the package signature after a successful install. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def _create_venv(venv_id, log) -> bool` + +**Purpose:** Create a Python virtual environment for one configured venv id. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _pip_install(python_path, packages, *, no_deps, log, label) -> bool` + +**Purpose:** Install one package list into a venv via pip. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _install_packages(venv_id, packages, packages_no_deps, log) -> bool` + +**Purpose:** Install regular and no-deps package lists for one venv id. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [Services/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/_index.md new file mode 100644 index 0000000..99c1fb6 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/_index.md @@ -0,0 +1,28 @@ +--- +title: "Settings" +draft: false +--- + +## Package `Settings` + +Sources under `Settings/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [console](console/) | `console.py` | ASLM Code module | +| [first_run](first_run/) | `first_run.py` | ASLM Code module | +| [host_locale](host_locale/) | `host_locale.py` | ASLM Code module | +| [host_theme](host_theme/) | `host_theme.py` | ASLM Code module | +| [mcp_json](mcp_json/) | `mcp_json.py` | ASLM Code module | +| [settings](settings/) | `settings.py` | ASLM Code module | +| [skills](skills/) | `skills.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/console.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/console.md new file mode 100644 index 0000000..670e489 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/console.md @@ -0,0 +1,58 @@ +--- +title: "console" +draft: false +--- + +## Module `console` + +`Settings/console.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Settings`. See **Related** for package index and callers. + +--- + +## Classes + +### `class PrintTechData` + +**Purpose:** Type `PrintTechData` defined in `console.py`. + +--- + +## Public functions + +#### `def PrintTechData.PTD_Print() -> None` + +**Purpose:** Print module manifest details and the current startup timestamp. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Private functions + +#### `def _load_module_manifest() -> dict[str, Any] | None` + +**Purpose:** Load the local module manifest when it exists and is valid JSON. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _print_separator() -> None` + +**Purpose:** Print a standard separator line for console output. + +--- + +## Related + +- [Settings/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/first_run.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/first_run.md new file mode 100644 index 0000000..5dc102d --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/first_run.md @@ -0,0 +1,64 @@ +--- +title: "first_run" +draft: false +--- + +## Module `first_run` + +`Settings/first_run.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Settings`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def run(log=…, ui_port=…, api_port=…) -> None` + +**Purpose:** Run the first-run setup workflow. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Private functions + +#### `def _build_initial_settings(existing, ui_port, api_port) -> dict[str, Any]` + +**Purpose:** Build the initial settings payload for the first run. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _print_warning(message) -> None` + +**Purpose:** Print a standardized bootstrap warning. + +#### `def _run_tool_bootstrap(log) -> None` + +**Purpose:** Run post-dependency bootstrap tasks for bundled tools. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _print_summary(settings_file, initial) -> None` + +**Purpose:** Print a short summary of the written first-run settings. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Related + +- [Settings/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/host_locale.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/host_locale.md new file mode 100644 index 0000000..1b9a61d --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/host_locale.md @@ -0,0 +1,77 @@ +--- +title: "host_locale" +draft: false +--- + +## Module `host_locale` + +`Settings/host_locale.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Settings`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def atomic_write_json(path, data) -> None` + +**Purpose:** Write JSON atomically via a temporary file and replace on success. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def save_host_locale_payload(data) -> None` + +**Purpose:** Persist the ASLM host locale snapshot next to module settings. + +**Steps:** + +1. Raise on invalid input or failure conditions. + +#### `def load_host_locale() -> dict[str, Any] | None` + +**Purpose:** Load the last persisted host locale snapshot, or None when missing or invalid. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def normalize_host_language(value) -> str` + +**Purpose:** Normalize a host language code to a supported value, defaulting to English. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def get_language() -> str` + +**Purpose:** Return the BCP-47 language code from the host locale snapshot. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_display_name() -> str | None` + +**Purpose:** Return the host-provided display name for the current language, when available. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [Settings/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/host_theme.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/host_theme.md new file mode 100644 index 0000000..9a9219a --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/host_theme.md @@ -0,0 +1,52 @@ +--- +title: "host_theme" +draft: false +--- + +## Module `host_theme` + +`Settings/host_theme.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Settings`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def atomic_write_json(path, data) -> None` + +**Purpose:** Write JSON atomically via a temporary file and replace on success. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def save_host_theme_payload(data) -> None` + +**Purpose:** Persist the ASLM host theme snapshot next to module settings. + +**Steps:** + +1. Raise on invalid input or failure conditions. + +#### `def load_host_theme() -> dict[str, Any] | None` + +**Purpose:** Load the last persisted host theme snapshot, or None when missing or invalid. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +--- + +## Related + +- [Settings/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/mcp_json.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/mcp_json.md new file mode 100644 index 0000000..a47ed85 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/mcp_json.md @@ -0,0 +1,118 @@ +--- +title: "mcp_json" +draft: false +--- + +## Module `mcp_json` + +`Settings/mcp_json.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Settings`. See **Related** for package index and callers. + +--- + +## Classes + +### `class UserMcpServerEntry` + +**Purpose:** Type `UserMcpServerEntry` defined in `mcp_json.py`. + +--- + +## Public functions + +#### `def ensure_default_mcp_json() -> None` + +**Purpose:** Create MCP/ and a default mcp.json when the file is missing. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def mcp_json_signature() -> tuple[str, int] | None` + +**Purpose:** Return path and mtime for cache invalidation, or None when the file is absent. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def load_raw_text() -> str` + +**Purpose:** Return mcp.json contents, creating a default file when needed. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def load_parsed() -> dict[str, Any]` + +**Purpose:** Parse mcp.json into a dictionary. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Parse or serialize JSON payloads. + +#### `def validate_mcp_document(data) -> None` + +**Purpose:** Raise ValueError when the document is not a valid MCP configuration. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Iterate and transform or accumulate state. + +#### `def iter_user_mcp_entries(reserved_ids) -> list[UserMcpServerEntry]` + +**Purpose:** Parse mcp.json and return user server entries with stable ids. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def save_raw_text(text) -> None` + +**Purpose:** Validate JSON and atomically write mcp.json. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +--- + +## Private functions + +#### `def _slugify(value) -> str` + +**Purpose:** Build a stable slug from a display name for MCP server ids. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _unique_server_id(base, taken) -> str` + +**Purpose:** Pick a unique server id that does not collide with reserved ids. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +--- + +## Related + +- [Settings/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/settings.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/settings.md new file mode 100644 index 0000000..9c6371d --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/settings.md @@ -0,0 +1,378 @@ +--- +title: "settings" +draft: false +--- + +## Module `settings` + +`Settings/settings.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Settings`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def normalize_setting_value(value) -> Any` + +**Purpose:** Normalize one raw settings value. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def normalize_setting_key(raw_key) -> str` + +**Purpose:** Normalize one raw settings key. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def normalize_engine_address(value) -> str` + +**Purpose:** Normalize one engine address for storage. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def normalize_backend_engine_name(engine) -> str` + +**Purpose:** Normalize one backend engine identifier. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def normalize_facade_engine_name(engine) -> str` + +**Purpose:** Normalize one facade engine identifier. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def normalize_engine_name(engine) -> str` + +**Purpose:** Backward-compatible alias for backend engine normalization. + +#### `def get_supported_engines() -> list[dict[str, str]]` + +**Purpose:** List facade engines supported by the UI. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_sub_engines() -> list[dict[str, str]]` + +**Purpose:** List backend engines exposed as ASLM-Chat sub-engines. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_enabled_engine_ids() -> list[str]` + +**Purpose:** List enabled engine identifiers from the effective settings. + +#### `def resolve_enabled_engine(engine, default=…) -> str` + +**Purpose:** Resolve one requested engine against the current enabled engine list. + +#### `def load_settings() -> dict[str, Any]` + +**Purpose:** Load the effective settings snapshot. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def save_settings(data) -> None` + +**Purpose:** Save the settings snapshot to disk. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def get(key, default=…) -> Any` + +**Purpose:** Read one setting value. + +#### `def set(key, value) -> None` + +**Purpose:** Persist one setting value. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def get_llm_engine(default=…) -> str` + +**Purpose:** Read the active facade LLM engine name. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_llm_sub_engine(default=…) -> str` + +**Purpose:** Read the active backend engine used inside ASLM-Chat. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_effective_backend_engine(facade_engine=…) -> str` + +**Purpose:** Resolve the backend engine used for ASLM-Chat proxy calls. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def is_facade_aslm_chat(facade_engine=…) -> bool` + +**Purpose:** Return whether the active facade engine delegates to ASLM-Chat. + +#### `def resolve_facade_engine(engine, default=…) -> str` + +**Purpose:** Resolve one requested facade engine. + +#### `def resolve_sub_engine(engine, default=…) -> str` + +**Purpose:** Resolve one requested backend sub-engine. + +#### `def get_engine_url_key(engine) -> str | None` + +**Purpose:** Resolve the settings key for one engine URL. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_engine_url(engine) -> str` + +**Purpose:** Build the effective engine URL. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_openai_api_key() -> str` + +**Purpose:** Read the OpenAI-compatible API key. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_google_genai_api_key() -> str` + +**Purpose:** Read the Google GenAI API key. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_engine_api_key_key(engine) -> str | None` + +**Purpose:** Resolve the settings key for one engine API key. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_engine_api_key(engine) -> str` + +**Purpose:** Read the configured API key for one engine. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_runtime_engine_settings() -> dict[str, Any]` + +**Purpose:** Build the runtime settings payload for the UI. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def get_console_log_level(default=…) -> str` + +**Purpose:** Read the console log level. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def is_console_debug_enabled() -> bool` + +**Purpose:** Check whether debug console output is enabled. + +#### `def is_console_trace_enabled() -> bool` + +**Purpose:** Check whether trace console output is enabled. + +#### `def is_engine_enabled(engine) -> bool` + +**Purpose:** Check whether one backend engine is enabled in local settings. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def is_ollama_engine(engine) -> bool` + +**Purpose:** Check whether the engine uses the Ollama adapter path. + +--- + +## Private functions + +#### `def _get_settings_mtime_ns() -> int | None` + +**Purpose:** Return the current settings file mtime. + +#### `def _store_settings_cache(data, mtime_ns) -> None` + +**Purpose:** Store one effective settings snapshot in memory. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _invalidate_settings_cache() -> None` + +**Purpose:** Invalidate the in-memory settings snapshot. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _get_enabled_engine_ids_from_settings(settings_data) -> list[str]` + +**Purpose:** List enabled engine identifiers from one settings snapshot. + +#### `def _resolve_enabled_engine_from_settings(settings_data, engine, default=…) -> str` + +**Purpose:** Resolve one engine against the enabled engine list. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _load_settings_from_disk() -> dict[str, Any]` + +**Purpose:** Read the settings payload from disk. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _apply_environment_overrides(data) -> dict[str, Any]` + +**Purpose:** Apply environment overrides to one settings snapshot. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _warn_port_collisions(settings) -> None` + +**Purpose:** Log a warning when two services share the same TCP port. + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Iterate and transform or accumulate state. + +#### `def _migrate_facade_engine_settings(data) -> dict[str, Any]` + +**Purpose:** Migrate legacy llm-engine values into facade + sub-engine settings. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_loaded_settings(data) -> dict[str, Any]` + +**Purpose:** Normalize a loaded settings snapshot (addresses, active engine, port checks). + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _to_env_var_name(key) -> str` + +**Purpose:** Build one runtime environment variable name. + +#### `def _serialize_env_value(value) -> str` + +**Purpose:** Serialize one value for environment storage. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +#### `def _apply_process_environment_value(key, value) -> None` + +**Purpose:** Apply one runtime setting to the current process environment. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _load_stored_settings_snapshot() -> dict[str, Any]` + +**Purpose:** Load stored settings without applying ASLM_ environment overrides. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _get_module_manifest_path() -> Path | None` + +**Purpose:** Locate the ASLM module manifest when available. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _sync_module_manifest_setting(key, value) -> None` + +**Purpose:** Mirror one runtime setting into the module manifest. + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Iterate and transform or accumulate state. +3. Parse or serialize JSON payloads. + +#### `def _infer_remote_scheme(value) -> str` + +**Purpose:** Infer a scheme for remote endpoints without one. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [Settings/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Settings/skills.md b/Docs/ASLM/content/docs/ASLM-Code/Settings/skills.md new file mode 100644 index 0000000..65b0176 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Settings/skills.md @@ -0,0 +1,446 @@ +--- +title: "skills" +draft: false +--- + +## Module `skills` + +`Settings/skills.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Settings`. See **Related** for package index and callers. + +--- + +## Classes + +### `class SkillFile` + +**Purpose:** Type `SkillFile` defined in `skills.py`. + +--- + +## Public functions + +#### `def ensure_skills_dir() -> Path` + +**Purpose:** Ensure the project-level Skills root directory exists. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def parse_front_matter(content) -> tuple[dict[str, Any], str]` + +**Purpose:** Parse a small YAML-like front matter block from skill markdown. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def list_skills() -> dict[str, Any]` + +**Purpose:** List all skill folders with metadata and file trees. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def create_skill_folder(name) -> dict[str, Any]` + +**Purpose:** Create a new skill folder with a default SKILL.md template. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def rename_skill_folder(old_name, new_name) -> dict[str, Any]` + +**Purpose:** Rename a skill folder and update its primary front matter name. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def delete_skill_folder(name) -> dict[str, Any]` + +**Purpose:** Delete one skill folder and its contents. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def create_skill_subdirectory(folder, dir_path) -> dict[str, Any]` + +**Purpose:** Create a subdirectory inside one skill folder. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def delete_skill_subdirectory(folder, dir_path) -> dict[str, Any]` + +**Purpose:** Delete a subdirectory inside one skill folder. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def rename_skill_item(folder, old_path, new_path, kind) -> dict[str, Any]` + +**Purpose:** Rename a file or directory inside one skill folder. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def read_skill_file(folder, file_path) -> dict[str, Any]` + +**Purpose:** Read one skill file with parsed front matter metadata. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def write_skill_file(folder, file_path, content) -> dict[str, Any]` + +**Purpose:** Write one skill file and return the updated skills listing. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def delete_skill_file(folder, file_path) -> dict[str, Any]` + +**Purpose:** Delete one skill file and prune empty parent directories. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. + +#### `def parse_enabled_flag(value) -> bool` + +**Purpose:** Parse a loose enabled flag from API or front matter input. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def set_skill_enabled(folder, enabled) -> dict[str, Any]` + +**Purpose:** Toggle whether one skill is enabled and refresh sandbox sync when needed. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. + +#### `def import_skill_files(skill_name, files) -> dict[str, Any]` + +**Purpose:** Create a skill folder from browser-imported path/content pairs. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Iterate and transform or accumulate state. + +#### `def clear_skill_config_refresh_pending() -> None` + +**Purpose:** Clear any queued one-shot skills summary refresh (tests and tooling). + +#### `def build_system_prompt_inventory() -> str` + +**Purpose:** Build a system-prompt block listing enabled skills and their on-disk layout. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def build_system_prompt_skills_section(*, consume=…, include_baseline=…) -> str` + +**Purpose:** Inject skills into the system prompt on the first turn or after enable toggles. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def build_system_prompt_skill_delta(*, consume=…, include_baseline=…) -> str` + +**Purpose:** Backward-compatible alias for build_system_prompt_skills_section. + +#### `def sync_skills_to_sandbox() -> dict[str, Any]` + +**Purpose:** Mirror project Skills into the sandbox Skills directory. + +--- + +## Private functions + +#### `def _is_hidden_part(part) -> bool` + +**Purpose:** Return True when a path segment is hidden or reserved. + +#### `def _validate_skill_name(name) -> str` + +**Purpose:** Validate and return a safe skill folder name. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _normalize_relative_file_path(path) -> str` + +**Purpose:** Normalize and validate a relative file path inside a skill folder. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _normalize_relative_dir_path(path) -> str` + +**Purpose:** Normalize and validate a relative directory path inside a skill folder. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _skill_dir(name) -> Path` + +**Purpose:** Resolve the on-disk directory for one skill name. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _skill_file_path(folder, file_path) -> Path` + +**Purpose:** Resolve an absolute path for one file inside a skill folder. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _skill_subdir_path(folder, dir_path) -> Path` + +**Purpose:** Resolve an absolute path for one subdirectory inside a skill folder. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _safe_read_text(path) -> str` + +**Purpose:** Read a text file with size and binary guards for the skills manager. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def _atomic_write_text(path, content) -> None` + +**Purpose:** Write text atomically via a temporary file in the target directory. + +**Steps:** + +1. Handle errors and map them to a safe response. + +#### `def _parse_scalar(value) -> Any` + +**Purpose:** Parse one YAML-like front matter scalar value. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_skill_source(meta) -> str` + +**Purpose:** Normalize the skill source field from front matter metadata. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _normalize_meta_for_storage(meta) -> dict[str, Any]` + +**Purpose:** Strip legacy front matter keys before persisting metadata. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _skill_created_at(stat) -> float` + +**Purpose:** Return the best available creation timestamp for a skill folder. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _format_front_matter(meta) -> str` + +**Purpose:** Render front matter metadata as a markdown header block. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _primary_file_for_skill(skill_root) -> Path` + +**Purpose:** Locate the primary markdown file for one skill folder. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _read_skill_meta(skill_root) -> tuple[dict[str, Any], str]` + +**Purpose:** Read normalized metadata and the primary file path for one skill. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _file_node(path, root) -> SkillFile` + +**Purpose:** Build one SkillFile node for the skills tree API. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_tree(path, root) -> list[dict[str, Any]]` + +**Purpose:** Build the nested file tree for one skill folder. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _format_skill_tree_lines(nodes, *, indent=…) -> list[str]` + +**Purpose:** Render enabled skill tree nodes as indented lines for the system prompt. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _pending_notify_path() -> Path` + +**Purpose:** Return the path used to queue a one-shot skills config refresh. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _load_notify_state() -> dict[str, Any]` + +**Purpose:** Load the pending skills notification state from disk. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _save_notify_state(state) -> None` + +**Purpose:** Persist or clear the pending skills notification state. + +**Steps:** + +1. Parse or serialize JSON payloads. + +#### `def _migrate_legacy_notify_state() -> None` + +**Purpose:** Migrate legacy notification files and re-queue refresh when needed. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def _peek_config_refresh_pending() -> bool` + +**Purpose:** Return whether a skills config refresh is pending without consuming it. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _consume_config_refresh_pending() -> bool` + +**Purpose:** Return and clear the pending skills config refresh flag. + +#### `def _queue_skill_config_refresh() -> None` + +**Purpose:** Queue a one-shot skills summary refresh for the next chat turn. + +#### `def _sha256_file(path) -> str` + +**Purpose:** Compute the SHA-256 digest of one file. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _enabled_skill_names(root) -> set[str]` + +**Purpose:** List skill folder names that are currently enabled. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _iter_sync_files(root, skill_names=…) -> dict[str, dict[str, Any]]` + +**Purpose:** Enumerate files under a skills root with size and hash metadata for sync. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Iterate and transform or accumulate state. + +#### `def _remove_tree_entry(path) -> None` + +**Purpose:** Remove one file or directory during sandbox sync cleanup. + +--- + +## Related + +- [Settings/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/_index.md new file mode 100644 index 0000000..a63fa2f --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/_index.md @@ -0,0 +1,23 @@ +--- +title: "Tools" +draft: false +--- + +## Package `Tools` + +Sources under `Tools/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [file_system](file_system/) | `Tools/file_system/` | Submodules | +| [update_model_runtime_metadata](update_model_runtime_metadata/) | `update_model_runtime_metadata.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/_index.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/_index.md new file mode 100644 index 0000000..a438b76 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/_index.md @@ -0,0 +1,26 @@ +--- +title: "file_system" +draft: false +--- + +## Package `file_system` + +Sources under `Tools/file_system/`. + +--- + +## Module map + +| Doc | Source | Role | +| --- | --- | --- | +| [fs_tools](fs_tools/) | `fs_tools.py` | ASLM Code module | +| [registry](registry/) | `registry.py` | ASLM Code module | +| [responses](responses/) | `responses.py` | ASLM Code module | +| [shell_tool](shell_tool/) | `shell_tool.py` | ASLM Code module | +| [workspace_paths](workspace_paths/) | `workspace_paths.py` | ASLM Code module | + +--- + +## Related + +- [_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/fs_tools.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/fs_tools.md new file mode 100644 index 0000000..ec88a04 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/fs_tools.md @@ -0,0 +1,61 @@ +--- +title: "fs_tools" +draft: false +--- + +## Module `fs_tools` + +`Tools/file_system/fs_tools.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Tools\file_system`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def read_file(path, start_line=…, end_line=…) -> dict[str, Any]` + +**Purpose:** Read a UTF-8 text file from the workspace, optionally a 1-based line slice. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def write_file(path, content) -> dict[str, Any]` + +**Purpose:** Create a new UTF-8 text file or fully overwrite an existing one. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def edit_file(path, old_str, new_str, replace_all=…) -> dict[str, Any]` + +**Purpose:** Replace an exact substring in a file; fail on missing or ambiguous matches. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def list_dir(path=…, recursive=…) -> dict[str, Any]` + +**Purpose:** List entries under a workspace directory, optionally walking recursively. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Iterate and transform or accumulate state. + +--- + +## Related + +- [file_system/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/registry.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/registry.md new file mode 100644 index 0000000..6446a55 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/registry.md @@ -0,0 +1,37 @@ +--- +title: "registry" +draft: false +--- + +## Module `registry` + +`Tools/file_system/registry.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Tools\file_system`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def handle_tool(tool_id, arguments=…) -> dict[str, Any]` + +**Purpose:** Execute one tool by id with keyword arguments, wrapping every failure. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def openai_tool_schemas() -> list[dict[str, Any]]` + +**Purpose:** Return the tool catalog projected into the OpenAI "tools" wire format. + +--- + +## Related + +- [file_system/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/responses.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/responses.md new file mode 100644 index 0000000..0377bd0 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/responses.md @@ -0,0 +1,52 @@ +--- +title: "responses" +draft: false +--- + +## Module `responses` + +`Tools/file_system/responses.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Tools\file_system`. See **Related** for package index and callers. + +--- + +## Classes + +### `class ToolError` + +**Purpose:** Type `ToolError` defined in `responses.py`. + +--- + +## Public functions + +#### `def ToolError.__str__() -> str` + +**Purpose:** Return the human-readable message for this error. + +#### `def success_response(tool, result=…, *, warnings=…, truncated=…) -> dict[str, Any]` + +**Purpose:** Wrap a successful tool result in the shared tool envelope. + +#### `def error_response(tool, error_type, message, *, result=…, warnings=…) -> dict[str, Any]` + +**Purpose:** Wrap a failed tool result in the shared tool envelope. + +#### `def exception_response(tool, exc) -> dict[str, Any]` + +**Purpose:** Map a raised Python exception into a typed tool error envelope. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [file_system/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/shell_tool.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/shell_tool.md new file mode 100644 index 0000000..7f1466b --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/shell_tool.md @@ -0,0 +1,63 @@ +--- +title: "shell_tool" +draft: false +--- + +## Module `shell_tool` + +`Tools/file_system/shell_tool.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Tools\file_system`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def run_command(command, cwd=…, timeout_s=…) -> dict[str, Any]` + +**Purpose:** Returns exit_code, stdout, stderr, elapsed_ms, and the resolved cwd. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. +3. Handle errors and map them to a safe response. +4. Spawn or communicate with a child process. + +--- + +## Private functions + +#### `def _resolve_shell() -> tuple[list[str], str]` + +**Purpose:** POSIX prefers bash, then falls back to sh. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _build_argv(command) -> tuple[list[str], str]` + +**Purpose:** PowerShell appends the user command after its UTF-8 bootstrap in the same -Command string. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _truncate(text) -> tuple[str, bool]` + +**Purpose:** Trim one output stream to the byte cap, returning the text and a truncated flag. + +**Steps:** + +1. Return the computed result to the caller. + +--- + +## Related + +- [file_system/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/workspace_paths.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/workspace_paths.md new file mode 100644 index 0000000..c8d9802 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/file_system/workspace_paths.md @@ -0,0 +1,45 @@ +--- +title: "workspace_paths" +draft: false +--- + +## Module `workspace_paths` + +`Tools/file_system/workspace_paths.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Tools\file_system`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def workspace_root() -> Path` + +**Purpose:** Defaults to a dedicated Workspace/ directory unless overridden by env. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def resolve_in_workspace(path) -> Path` + +**Purpose:** Accepts plain relative paths; absolute paths must stay within the workspace. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Return the computed result to the caller. + +#### `def to_relative(path) -> str` + +**Purpose:** Return one absolute workspace path as a clean root-relative POSIX string. + +--- + +## Related + +- [file_system/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/Tools/update_model_runtime_metadata.md b/Docs/ASLM/content/docs/ASLM-Code/Tools/update_model_runtime_metadata.md new file mode 100644 index 0000000..f195e46 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/Tools/update_model_runtime_metadata.md @@ -0,0 +1,132 @@ +--- +title: "update_model_runtime_metadata" +draft: false +--- + +## Module `update_model_runtime_metadata` + +`Tools/update_model_runtime_metadata.py` — ASLM Code Python module. + +--- + +## Overview + +Part of `Tools`. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def main() -> int` + +**Purpose:** Implements `main` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. +2. Parse or serialize JSON payloads. + +--- + +## Private functions + +#### `def _read_json_file(path) -> dict[str, Any]` + +**Purpose:** Implements `_read_json_file` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _manifest_setting(manifest, key) -> Any` + +**Purpose:** Implements `_manifest_setting` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _runtime_setting(settings, manifest, key, default=…, *, env_key=…) -> Any` + +**Purpose:** Implements `_runtime_setting` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _coerce_port(value) -> int | None` + +**Purpose:** Implements `_coerce_port` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +#### `def _local_route_url(port, route) -> str` + +**Purpose:** Implements `_local_route_url` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _source_descriptor(name, route, port_key) -> dict[str, Any]` + +**Purpose:** Implements `_source_descriptor` in `update_model_runtime_metadata.py`. + +#### `def _fetch_json(url, *, method=…, body=…) -> dict[str, Any]` + +**Purpose:** Implements `_fetch_json` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. +3. Parse or serialize JSON payloads. + +#### `def _ollama_base_url(settings, manifest) -> str` + +**Purpose:** Implements `_ollama_base_url` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _find_loaded_ollama_model(models, model_name) -> dict[str, Any]` + +**Purpose:** Implements `_find_loaded_ollama_model` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. +2. Iterate and transform or accumulate state. + +#### `def _active_model_key(engine, model_name) -> str` + +**Purpose:** Implements `_active_model_key` in `update_model_runtime_metadata.py`. + +#### `def _build_metadata() -> dict[str, Any]` + +**Purpose:** Implements `_build_metadata` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _write_json_atomic(path, payload) -> None` + +**Purpose:** Implements `_write_json_atomic` in `update_model_runtime_metadata.py`. + +**Steps:** + +1. Parse or serialize JSON payloads. + +--- + +## Related + +- [Tools/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/_index.md b/Docs/ASLM/content/docs/ASLM-Code/_index.md new file mode 100644 index 0000000..2ba41a2 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/_index.md @@ -0,0 +1,62 @@ +--- +title: "ASLM-Code" +draft: false +icon: "developer_board" +weight: 101 +--- + +Python and JavaScript sources for the **ASLM Code** module (`aslm-code`). + +| Section | Doc | +| --- | --- | +| [main](main/) | Host CLI entry (`runserver`, `first_run`, settings bridge, server venv re-exec) | +| [manage](manage/) | Django `manage.py` shim | +| [API](API/) | MCP tool registry exposed to the UI | +| [ASLM](ASLM/) | Django project package (`settings`, `urls`, ASGI/WSGI) | +| [Apps](Apps/) | Django apps and client static assets | +| [Runtime](Runtime/) | Run manager, execution backends, and engine executors | +| [Services](Services/) | ASLM-Chat interop, venvs, MCP workers, host bridges | +| [Settings](Settings/) | `settings.json`, first run, MCP, skills, host snapshots | +| [Tools](Tools/) | File-system tool server and runtime metadata helpers | + +--- + +## Architecture overview + +ASLM Code runs as a Django app inside the ASLM host. The host launches `main.py`, which re-execs into the server venv and starts `runserver`. The browser loads `Apps/UI` templates and `static/js` modules. Coding turns flow through `Apps/UI/views.py`, which persists messages in `Apps/Data`, composes prompts (skills, uploads, workspace context), and dispatches a run through [Runtime](Runtime/). The run manager selects an executor — primarily [`aslm_chat_executor`](Runtime/executors/aslm_chat_executor/), which streams generation from the sibling **ASLM-Chat** module via [Services](Services/) (`aslm_chat_client`, `aslm_chat_resolver`, `aslm_chat_stream`). Tool calls go through [`API/mcp`](API/mcp/) and the file-system tools under [`Tools/file_system`](Tools/file_system/), executed by `Services/tool_worker.py` or external user MCP servers. + +--- + +## Documentation conventions + +Documentation paths **mirror** the repository tree: `path/to/module.py` → `Docs/.../ASLM-Code/path/to/module.md` (or `file.js` → `file.md`). + +| Artifact | Rule | +| --- | --- | +| Package directory | `_index.md` with **Module map** so Hugo keeps full menu depth | +| `tests/test_*.py` | `tests/test_foo.md` with **## Test methods** | +| Single `tests.py` | `tests.md` with **## Test methods** and `####` per test | +| `__init__.py` | Not documented — no `__init__.md` | +| Migrations | Not documented | + +Reference pages follow the same outline as [ASLM C# documentation](https://github.com/nickel-grove/ASLM) (`Docs/ASLM` in the ASLM repo): + +| Level | Use for | +| --- | --- | +| `## Module \`name\`` / `## File \`name.js\`` | Leaf page title | +| `## Overview` | Pipeline or role for large modules | +| `## Classes` | Types; `### \`class Name\`` for summary | +| `## Public functions` / `## Private functions` | Grouped members | +| `#### \`signature\`` | One block per function with **Purpose:** and **Steps:** when non-trivial | +| `## Test methods` | Test modules (`test_*.py`) | +| `## Related` | Parent `_index` first | + +**Markdown:** use normal Hugo markdown — no blank lines between rows of one table or items in one list; blank lines only between sections or adjacent `####` blocks. + +Do **not** use `## \`function_name\`` in the sidebar (use `####` under Public/Private only). + +--- + +## Related + +- [Documentation home](../) diff --git a/Docs/ASLM/content/docs/ASLM-Code/main.md b/Docs/ASLM/content/docs/ASLM-Code/main.md new file mode 100644 index 0000000..81bece4 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/main.md @@ -0,0 +1,181 @@ +--- +title: "main" +draft: false +--- + +## Module `main` + +`main.py` — ASLM Code Python module. + +--- + +## Overview + +Top-level module of the ASLM-Code repository. See **Related** for package index and callers. + +--- + +## Classes + +### `class LazyDjangoApplication` + +**Purpose:** Bind the UI port first, then hand requests to Django once it is ready. + +--- + +## Public functions + +#### `def run_django_command(*args, log=…) -> None` + +**Purpose:** Execute a Django management command. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LazyDjangoApplication.__init__() -> None` + +**Purpose:** Implements `LazyDjangoApplication.__init__` in `main.py`. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LazyDjangoApplication.load_in_background() -> None` + +**Purpose:** Start loading Django without blocking the listening socket. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def LazyDjangoApplication.__call__(environ, start_response)` + +**Purpose:** Implements `LazyDjangoApplication.__call__` in `main.py`. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def cmd_runserver(port, log) -> None` + +**Purpose:** Start the Django development server on the requested port. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def cmd_migrate(log) -> None` + +**Purpose:** Apply all pending database migrations. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def cmd_makemigrations(app, log) -> None` + +**Purpose:** Create migration files for changed models. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def cmd_collectstatic(log) -> None` + +**Purpose:** Collect static files into ``STATIC_ROOT``. + +#### `def cmd_first_run(log=…, ui_port=…, api_port=…) -> None` + +**Purpose:** Generate settings and apply initial migrations. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def cmd_get_setting(key) -> None` + +**Purpose:** Print a single setting value for ASLM integration hooks. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def cmd_set_setting(key, value) -> None` + +**Purpose:** Update a single setting key from string input. + +**Steps:** + +1. Execute the implementation in the source module. + +#### `def cmd_apply_aslm_host_theme(theme_file) -> None` + +**Purpose:** Apply a JSON theme snapshot written by ASLM (temp file path in ``--file``). + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Parse or serialize JSON payloads. + +#### `def cmd_apply_aslm_locale(locale_file) -> None` + +**Purpose:** Apply a JSON locale snapshot written by ASLM (temp file path in ``--file``). + +**Steps:** + +1. Handle errors and map them to a safe response. +2. Parse or serialize JSON payloads. + +#### `def main() -> None` + +**Purpose:** Parse CLI arguments and dispatch the requested command. + +**Steps:** + +1. Execute the implementation in the source module. + +--- + +## Private functions + +#### `def _maybe_reexec_in_server_venv(command) -> None` + +**Purpose:** Delegate the current command to ASLM-Code's server venv when required. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Handle errors and map them to a safe response. +3. Spawn or communicate with a child process. + +#### `def LazyDjangoApplication._load() -> None` + +**Purpose:** Implements `LazyDjangoApplication._load` in `main.py`. + +#### `def _build_parser() -> argparse.ArgumentParser` + +**Purpose:** Return the command-line parser for the project entry point. + +**Steps:** + +1. Return the computed result to the caller. + +#### `def _maybe_print_banner(command) -> None` + +**Purpose:** Print technical module data once for interactive commands. + +#### `def _resolve_runserver_port(requested_port) -> int` + +**Purpose:** Return the effective UI port for ``runserver``. + +**Steps:** + +1. Return the computed result to the caller. +2. Handle errors and map them to a safe response. + +--- + +## Related + +- [ASLM-Code/_index](../_index/) diff --git a/Docs/ASLM/content/docs/ASLM-Code/manage.md b/Docs/ASLM/content/docs/ASLM-Code/manage.md new file mode 100644 index 0000000..14256a3 --- /dev/null +++ b/Docs/ASLM/content/docs/ASLM-Code/manage.md @@ -0,0 +1,41 @@ +--- +title: "manage" +draft: false +--- + +## Module `manage` + +`manage.py` — ASLM Code Python module. + +--- + +## Overview + +Top-level module of the ASLM-Code repository. See **Related** for package index and callers. + +--- + +## Public functions + +#### `def main() -> None` + +**Purpose:** Run Django administrative tasks. + +**Steps:** + +1. Raise on invalid input or failure conditions. +2. Handle errors and map them to a safe response. + +--- + +## Private functions + +#### `def _configure_settings_module() -> None` + +**Purpose:** Set the default Django settings module for management commands. + +--- + +## Related + +- [ASLM-Code/_index](../_index/) diff --git a/Docs/ASLM/content/docs/PatchNotes/202606261606-Docs-CI-Fix.md b/Docs/ASLM/content/docs/PatchNotes/202606261606-Docs-CI-Fix.md new file mode 100644 index 0000000..824d03f --- /dev/null +++ b/Docs/ASLM/content/docs/PatchNotes/202606261606-Docs-CI-Fix.md @@ -0,0 +1,23 @@ +--- +title: "Docs CI Pipeline Fix" +date: 2026-06-26T16:06:37Z +draft: false +description: "Summary of changes to the Docs CI pipeline to address issues with large inputs." +--- + +## New Features + +* No new features in this release. + +## Bug Fixes + +* **Docs CI Pipeline**: Addressed an issue in the Jules CI workflows (`jules-update-docs.yml` and `jules-update-patchnotes.yml`) where oversized commit diffs could exceed API and shell limits. Implemented truncation for large file lists (capped at 16,384 characters) and commit diffs (capped at 524,288 characters) before they are passed into prompts. +* **Docs CI Pipeline**: Fixed an issue with passing long, multi-line prompts via GitHub Outputs. The workflows now write the prompt to a temporary file (`jules_prompt.txt`) and construct the JSON payload using `jq --rawfile` instead of reading from environment variables. + +## API Changes + +* No API changes in this release. + +## Known Issues + +* No known issues at this time. diff --git a/Docs/ASLM/content/docs/PatchNotes/202606261740-pr-sync-docs.md b/Docs/ASLM/content/docs/PatchNotes/202606261740-pr-sync-docs.md new file mode 100644 index 0000000..506e3ca --- /dev/null +++ b/Docs/ASLM/content/docs/PatchNotes/202606261740-pr-sync-docs.md @@ -0,0 +1,18 @@ +--- +title: "Fix PR Sync Docs Merge Handling" +date: 2026-06-26T17:40:50Z +draft: false +description: "Updated pr-sync-docs workflow to skip branches with squash merge conflicts instead of failing the workflow." +--- + +## New Features +- None + +## Bug Fixes +- **pr-sync-docs workflow:** Improved merge conflict handling. The workflow will now drop the branch and continue processing other branches when a squash merge conflict occurs, rather than failing the entire workflow. + +## API Changes +- None + +## Known Issues +- None diff --git a/Docs/ASLM/content/docs/PatchNotes/_index.md b/Docs/ASLM/content/docs/PatchNotes/_index.md new file mode 100644 index 0000000..0b3e157 --- /dev/null +++ b/Docs/ASLM/content/docs/PatchNotes/_index.md @@ -0,0 +1,7 @@ +--- +title: "Patch Notes" +draft: false +icon: "history" +weight: 200 +paginate: 30 +--- diff --git a/Docs/ASLM/content/docs/_index.md b/Docs/ASLM/content/docs/_index.md new file mode 100644 index 0000000..596f2c1 --- /dev/null +++ b/Docs/ASLM/content/docs/_index.md @@ -0,0 +1,19 @@ +--- +title: "ASLM Code documentation" +draft: false +--- + +**ASLM Code** (`aslm-code`) is an official **ASLM host module** for local coding assistance: a Django web UI, SQLite data layer, a run/execution runtime, file-system tools, and MCP integration. It does **not** run model inference itself — it delegates LLM generation to the **ASLM-Chat** module over the ASLM module-interop protocol. The host loads the module from `ASLM_Module.json` and runs [`main`](../ASLM-Code/main/) inside the ASLM desktop shell. + +This site documents the **ASLM-Code repository** (Python and client-side JavaScript) and **patch notes**. + +--- + +## Terminology + +| Name | Meaning | +| --- | --- | +| **ASLM** (host) | The Windows desktop host in the main ASLM repository | +| **ASLM Code** (module) | This coding-assistant module (`aslm-code`) | +| **ASLM Chat** (module) | The sibling chat module (`aslm-chat`) that ASLM-Code delegates inference to | +| **`ASLM/` package** | Django project package in this repo — not the MAUI host application | diff --git a/Docs/ASLM/data/landing.yaml b/Docs/ASLM/data/landing.yaml new file mode 100644 index 0000000..0722437 --- /dev/null +++ b/Docs/ASLM/data/landing.yaml @@ -0,0 +1,46 @@ +# Hero +hero: + enable: true + weight: 10 + template: hero + + backgroundImage: + path: "images/templates/hero" + filename: + desktop: "gradient-desktop.webp" + mobile: "gradient-mobile.webp" + + badge: + text: v0.1.0 + color: primary + pill: false + soft: true + + title: "ASLM Code" + subtitle: "Welcome to ASLM Code Docs" + + image: + path: "images" + filename: "lotus_docs_screenshot.png" + alt: "Lotus Docs Screenshot" + boxShadow: true + rounded: true + + ctaButton: + icon: menu_book + btnText: "Documentation" + url: "/docs/" + cta2Button: + icon: feed + btnText: "Patch Notes" + url: "/docs/patchnotes/" + + info: "**Copyright NGGT.LightKeeper. All Rights Reserved.**" + +# Feature Grid +featureGrid: + enable: false + +# Image compare +imageCompare: + enable: false diff --git a/Docs/ASLM/go.mod b/Docs/ASLM/go.mod new file mode 100644 index 0000000..bcd13de --- /dev/null +++ b/Docs/ASLM/go.mod @@ -0,0 +1,8 @@ +module github.com/NGGTLightKeeper/ASLM + +go 1.25.3 + +require ( + github.com/colinwilson/lotusdocs v0.3.0 // indirect + github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20800 // indirect +) diff --git a/Docs/ASLM/go.sum b/Docs/ASLM/go.sum new file mode 100644 index 0000000..eaa410c --- /dev/null +++ b/Docs/ASLM/go.sum @@ -0,0 +1,11 @@ +github.com/colinwilson/lotusdocs v0.2.0 h1:vG/frwOUKPRpF3xuXk177Pw73aFrFcT2zRgTI9FiiMY= +github.com/colinwilson/lotusdocs v0.2.0/go.mod h1:hGOYA9Ym3MA3YGmm9YHo9HkJxlHCyPNaYeFwvn/IFJY= +github.com/colinwilson/lotusdocs v0.3.0 h1:O8XXKEzflGLZFfS6yqoSZt/AGHG7Nku1+UlOpAxosTk= +github.com/colinwilson/lotusdocs v0.3.0/go.mod h1:hGOYA9Ym3MA3YGmm9YHo9HkJxlHCyPNaYeFwvn/IFJY= +github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20400 h1:L6+F22i76xmeWWwrtijAhUbf3BiRLmpO5j34bgl1ggU= +github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20400/go.mod h1:uekq1D4ebeXgduLj8VIZy8TgfTjrLdSl6nPtVczso78= +github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20800 h1:j5myhhzYwIHTr5ctK96Elfgp5uRROvrlTzYwwe1nF8o= +github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20800/go.mod h1:P5GGyhdxi00C5zW7vkRo/IS532gZY/YS2TS395Xaxho= +github.com/gohugoio/hugo-mod-jslibs-dist/popperjs/v2 v2.21100.20000/go.mod h1:mFberT6ZtcchrsDtfvJM7aAH2bDKLdOnruUHl0hlapI= +github.com/twbs/bootstrap v5.3.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= +github.com/twbs/bootstrap v5.3.8+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= diff --git a/Docs/ASLM/hugo.toml b/Docs/ASLM/hugo.toml new file mode 100644 index 0000000..0df597d --- /dev/null +++ b/Docs/ASLM/hugo.toml @@ -0,0 +1,30 @@ +baseURL = 'http://example.org/' +languageCode = 'en-us' +title = 'ASLM Documentation' +contentDir = 'content' +enableEmoji = true + +[module] + [[module.imports]] + path = "github.com/colinwilson/lotusdocs" + disable = false + [[module.imports]] + path = "github.com/gohugoio/hugo-mod-bootstrap-scss/v5" + disable = false + +[markup] + [markup.tableOfContents] + # Page title is h1; show h2–h3 in TOC (class sections), not every method (h4). + endLevel = 3 + startLevel = 2 + [markup.goldmark] + [markup.goldmark.renderer] + unsafe = true + [markup.goldmark.parser] + [markup.goldmark.parser.attribute] + block = true + +[params.docs] + darkMode = true + # Nested sidebar dropdown levels (default in partial: 6). Deeper branches flatten to links. + sidebarMaxDepth = 10 diff --git a/Docs/ASLM/layouts/docs/patchnotes/list.html b/Docs/ASLM/layouts/docs/patchnotes/list.html new file mode 100644 index 0000000..b8de6cc --- /dev/null +++ b/Docs/ASLM/layouts/docs/patchnotes/list.html @@ -0,0 +1,22 @@ +{{ define "main" }} + +{{ end }} diff --git a/Docs/ASLM/layouts/partials/docs/head.html b/Docs/ASLM/layouts/partials/docs/head.html new file mode 100644 index 0000000..f575af6 --- /dev/null +++ b/Docs/ASLM/layouts/partials/docs/head.html @@ -0,0 +1,118 @@ + + + + {{- $url := replace .Permalink ( printf "%s" .Site.BaseURL) "" }} + {{- if eq $url "/" }} + {{- .Site.Title }} + {{- else }} + {{- if .Params.heading }} + {{ .Params.heading }} + {{ else }} + {{- if eq .Title .Site.Title }} + {{- .Title }} + {{- else }} + {{- .Title }} | {{ .Site.Params.docs.Title | default (.Site.Title) }} + {{- end }} + {{- end }} + {{- end -}} + + {{- if not hugo.IsProduction }} + + {{- end }} + + {{- with .Description | default ($.Param "description") }} + + {{- end }} + + + + + + + {{ block "favicon" . }}{{ partialCached (printf "%s/%s" ($.Scratch.Get "pathName") "head/favicon.html") . }}{{ end }} + {{- partial (printf "%s/%s" ($.Scratch.Get "pathName") "head/opengraph") . }} + {{- partial (printf "%s/%s" ($.Scratch.Get "pathName") "head/twitter_cards") . }} + + {{- with .Site.Title }} + + {{- end }} + + {{ if eq .Site.Params.docs.darkMode true -}} + {{ $darkModeInit := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/darkmode-init.js") | js.Build | minify -}} + + {{ end -}} + + {{ if or (not (isset .Site.Params.flexsearch "enabled")) (eq .Site.Params.flexsearch.enabled true) -}} + {{ if and (.Site.Params.docsearch.appID) (.Site.Params.docsearch.apiKey) -}} + {{ else }} + {{ $flexSearch := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/flexsearch.bundle.js") }} + {{- if not hugo.IsServer }} + {{ $flexSearch := $flexSearch | minify | fingerprint "sha384" }} + + {{ else }} + + {{ end }} + {{ end }} + {{ end }} + + {{- partialCached "google-fonts" . }} + + {{- $options := dict "enableSourceMap" true }} + {{- if hugo.IsProduction}} + {{- $options := dict "enableSourceMap" false "outputStyle" "compressed" }} + {{- end }} + {{- $style := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/style.scss") }} + {{- $style = $style | resources.ExecuteAsTemplate (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/style.scss") . | css.Sass $options }} + {{- if hugo.IsProduction }} + {{- $style = $style | minify | fingerprint "sha384" }} + {{- end -}} + + {{- $aslmOverrides := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/custom/aslm-overrides.scss") | css.Sass $options }} + {{- if hugo.IsProduction }} + {{- $aslmOverrides = $aslmOverrides | minify | fingerprint "sha384" }} + {{- end -}} + + + {{- if .Params.katex -}} + {{- $options := dict "enableSourceMap" true }} + {{- if hugo.IsProduction}} + {{- $options := dict "enableSourceMap" false "outputStyle" "compressed" }} + {{- end -}} + {{- $katexCSS := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/katex.scss") }} + {{- $katexCSS = $katexCSS | resources.ExecuteAsTemplate (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/katex.scss") . | css.Sass $options }} + {{- if hugo.IsProduction }} + {{- $katexCSS = $katexCSS | minify | fingerprint "sha384" }} + {{- end -}} + + {{- end -}} + + {{- if .Params.katex -}} + {{ $katex := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/katex.js") }} + {{ $katexAutoRender := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/auto-render.js") }} + {{ if hugo.IsProduction }} + {{ $katex = $katex | minify | fingerprint "sha384" }} + {{ $katexAutoRender = $katexAutoRender | minify | fingerprint "sha384" }} + {{- end -}} + + + {{ end -}} + + + {{ if .Params.katex }} + {{- partialCached (printf "%s/%s" ($.Scratch.Get "pathName") "footer/katex.html") . -}} + {{ end }} + + {{- if not hugo.IsServer }} + {{- if or (.Site.Params.plausible.scriptPath) (.Site.Params.plausible.src) -}} + {{- partialCached (printf "%s/%s" ($.Scratch.Get "pathName") "head/plausible_v3.1.0") . }} + {{ else if and (.Site.Params.plausible.scriptURL | default "https://plausible.io") (.Site.Params.plausible.dataDomain) -}} + {{- partialCached (printf "%s/%s" ($.Scratch.Get "pathName") "head/plausible") . }} + {{- end -}} + {{- end -}} + + {{- if not hugo.IsServer }} + {{- if .Site.Config.Services.GoogleAnalytics.ID }} + {{- template "_internal/google_analytics.html" . -}} + {{- end -}} + {{- end -}} + diff --git a/Docs/ASLM/layouts/partials/docs/is-patchnotes-branch.html b/Docs/ASLM/layouts/partials/docs/is-patchnotes-branch.html new file mode 100644 index 0000000..8f33f26 --- /dev/null +++ b/Docs/ASLM/layouts/partials/docs/is-patchnotes-branch.html @@ -0,0 +1,10 @@ +{{- /* Returns "true" when $node is the Patch Notes section (listing its note pages). */ -}} +{{- $node := .node -}} +{{- if not $node -}}false{{- else if eq $node.Title "Patch Notes" -}}true{{- else -}} +{{- $dir := "" -}} +{{- with $node.File -}} + {{- $dir = .Dir | replace "\\" "/" | strings.TrimSuffix "/" -}} +{{- end -}} +{{- $rel := $node.RelPermalink | default "" | replace "\\" "/" -}} +{{- if or (eq $dir "docs/PatchNotes") (strings.Contains $rel "/docs/patchnotes") -}}true{{- else -}}false{{- end -}} +{{- end -}} diff --git a/Docs/ASLM/layouts/partials/docs/sidebar-sort-mode.html b/Docs/ASLM/layouts/partials/docs/sidebar-sort-mode.html new file mode 100644 index 0000000..7183f6b --- /dev/null +++ b/Docs/ASLM/layouts/partials/docs/sidebar-sort-mode.html @@ -0,0 +1,10 @@ +{{- /* + Returns one token (no whitespace): root-weight | title + Patch Notes sorting is handled separately via is-patchnotes-branch.html +*/ -}} +{{- $node := .node -}} +{{- if not $node -}}title{{- else -}} +{{- $dir := $node.File.Dir | default "" | replace "\\" "/" | strings.TrimSuffix "/" -}} +{{- $rel := $node.RelPermalink | default "" | replace "\\" "/" | strings.TrimSuffix "/" -}} +{{- if or (eq $dir "docs") (eq $rel "/docs") -}}root-weight{{- else -}}title{{- end -}} +{{- end -}} diff --git a/Docs/ASLM/layouts/partials/docs/sidebar-tree-children.html b/Docs/ASLM/layouts/partials/docs/sidebar-tree-children.html new file mode 100644 index 0000000..3349a14 --- /dev/null +++ b/Docs/ASLM/layouts/partials/docs/sidebar-tree-children.html @@ -0,0 +1,58 @@ +{{- /* + Renders deduplicated children of a sidebar branch. + Subsections (.Sections) first, then leaf pages (.Pages) not already listed. +*/ -}} +{{- $node := .node -}} +{{- $current := .current -}} +{{- $depth := .depth -}} +{{- $maxDepth := .maxDepth -}} +{{- $sidebarIcons := .sidebarIcons -}} +{{- $noIconClass := "" -}} +{{- if not $sidebarIcons }}{{ $noIconClass = "no-icon" }}{{ end -}} +{{- $patchNotesBranch := eq (partial "docs/is-patchnotes-branch.html" (dict "node" $node) | strings.TrimSpace) "true" -}} +{{- $sortMode := partial "docs/sidebar-sort-mode.html" (dict "node" $node) | strings.TrimSpace -}} +{{- $seen := dict -}} + +{{- if $patchNotesBranch -}} + {{- $sortedPages := partial "docs/sort-patchnotes-pages.html" $node.Pages -}} + {{- range $sortedPages -}} + {{- $key := .RelPermalink -}} + {{- if not (index $seen $key) -}} + {{- $seen = merge $seen (dict $key true) -}} + {{- $childActive := in $current.RelPermalink .RelPermalink -}} +
  • + {{ .Title }} +
  • + {{- end -}} + {{- end -}} +{{- else if eq $sortMode "root-weight" -}} + {{- range $node.Sections.ByWeight -}} + {{- $key := .RelPermalink -}} + {{- if not (index $seen $key) -}} + {{- $seen = merge $seen (dict $key true) -}} + {{- partial "docs/sidebar-tree.html" (dict "node" . "current" $current "depth" $depth "maxDepth" $maxDepth "sidebarIcons" $sidebarIcons) -}} + {{- end -}} + {{- end -}} + {{- range $node.Pages.ByWeight -}} + {{- $key := .RelPermalink -}} + {{- if not (index $seen $key) -}} + {{- $seen = merge $seen (dict $key true) -}} + {{- partial "docs/sidebar-tree.html" (dict "node" . "current" $current "depth" $depth "maxDepth" $maxDepth "sidebarIcons" $sidebarIcons) -}} + {{- end -}} + {{- end -}} +{{- else -}} + {{- range $node.Sections.ByTitle -}} + {{- $key := .RelPermalink -}} + {{- if not (index $seen $key) -}} + {{- $seen = merge $seen (dict $key true) -}} + {{- partial "docs/sidebar-tree.html" (dict "node" . "current" $current "depth" $depth "maxDepth" $maxDepth "sidebarIcons" $sidebarIcons) -}} + {{- end -}} + {{- end -}} + {{- range $node.Pages.ByTitle -}} + {{- $key := .RelPermalink -}} + {{- if not (index $seen $key) -}} + {{- $seen = merge $seen (dict $key true) -}} + {{- partial "docs/sidebar-tree.html" (dict "node" . "current" $current "depth" $depth "maxDepth" $maxDepth "sidebarIcons" $sidebarIcons) -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/Docs/ASLM/layouts/partials/docs/sidebar-tree.html b/Docs/ASLM/layouts/partials/docs/sidebar-tree.html new file mode 100644 index 0000000..50d61c2 --- /dev/null +++ b/Docs/ASLM/layouts/partials/docs/sidebar-tree.html @@ -0,0 +1,109 @@ +{{- /* + Recursive sidebar node. Expects dict: + node, current, depth, maxDepth, sidebarIcons +*/ -}} +{{- $node := .node -}} +{{- $current := .current -}} +{{- $depth := .depth -}} +{{- $maxDepth := .maxDepth -}} +{{- $sidebarIcons := .sidebarIcons -}} +{{- $patchNotesBranch := eq (partial "docs/is-patchnotes-branch.html" (dict "node" $node) | strings.TrimSpace) "true" -}} +{{- $sortMode := partial "docs/sidebar-sort-mode.html" (dict "node" $node) | strings.TrimSpace -}} +{{- $hasChildren := or $node.Sections $node.Pages -}} +{{- $active := in $current.RelPermalink $node.RelPermalink -}} +{{- $canNest := lt $depth $maxDepth -}} +{{- $noIconClass := "" -}} +{{- if not $sidebarIcons }}{{ $noIconClass = "no-icon" }}{{ end -}} +{{- $childDict := dict "node" $node "current" $current "depth" (add $depth 1) "maxDepth" $maxDepth "sidebarIcons" $sidebarIcons -}} + +{{- if and $hasChildren $canNest -}} + +{{- else if $hasChildren -}} + +{{- else -}} +
  • + {{- if eq $depth 0 -}} + + {{- if $sidebarIcons -}} + {{ $node.Params.icon }} + {{- end -}} + {{ $node.Title }} + + {{- else -}} + {{ $node.Title }} + {{- end -}} +
  • +{{- end -}} diff --git a/Docs/ASLM/layouts/partials/docs/sidebar.html b/Docs/ASLM/layouts/partials/docs/sidebar.html new file mode 100644 index 0000000..37dd2f8 --- /dev/null +++ b/Docs/ASLM/layouts/partials/docs/sidebar.html @@ -0,0 +1,28 @@ + + diff --git a/Docs/ASLM/layouts/partials/docs/sort-patchnotes-pages.html b/Docs/ASLM/layouts/partials/docs/sort-patchnotes-pages.html new file mode 100644 index 0000000..1d00ef5 --- /dev/null +++ b/Docs/ASLM/layouts/partials/docs/sort-patchnotes-pages.html @@ -0,0 +1,5 @@ +{{- /* + Patch note pages: YYYYMMDDHHmm filename prefix, newest first. + Expects a page collection (e.g. .Pages). +*/ -}} +{{- return (sort . ".File.ContentBaseName" "desc") -}} diff --git a/Docs/DocsWebServerASLM.ps1 b/Docs/DocsWebServerASLM.ps1 new file mode 100644 index 0000000..d40cffe --- /dev/null +++ b/Docs/DocsWebServerASLM.ps1 @@ -0,0 +1,79 @@ +# ================================================================= +# PowerShell Script: DocsWebServerASLM.ps1 +# +# Checks for Chocolatey and Hugo Extended, then starts the Hugo +# development server for ASLM documentation. +# +# Re-launches as Administrator when elevation is required. +# ================================================================= +param([switch]$Elevated) + +function Test-Admin { + $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object System.Security.Principal.WindowsPrincipal($identity) + return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) +} + +if (-not (Test-Admin)) { + if ($Elevated) { + Write-Warning "Failed to elevate to administrator privileges. Please run as Administrator." + Read-Host "Press Enter to exit" + } else { + Start-Process powershell.exe -Verb RunAs -ArgumentList ('-ExecutionPolicy Bypass -NoProfile -File "{0}" -Elevated' -f ($myinvocation.MyCommand.Definition)) + } + exit +} + +$Host.UI.RawUI.WindowTitle = "ASLM Docs Web Server Launcher" +Clear-Host + +$hugoProjectPath = Join-Path $PSScriptRoot "ASLM" + +Write-Host "Checking for Chocolatey package manager..." -ForegroundColor Yellow +$chocoPath = Get-Command choco -ErrorAction SilentlyContinue +if (-not $chocoPath) { + Write-Host "Chocolatey not found. Proceeding with installation." -ForegroundColor Cyan + Write-Host "Installing Chocolatey... Please wait, this may take a few minutes." -ForegroundColor Cyan + Set-ExecutionPolicy Bypass -Scope Process -Force + [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072 + iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + if ($LASTEXITCODE -ne 0) { + Write-Error "Chocolatey installation failed. Please try installing it manually from chocolatey.org" + Read-Host "Press Enter to exit" + exit 1 + } + Write-Host "Chocolatey installed successfully." -ForegroundColor Green + $env:Path = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Environment]::GetEnvironmentVariable("Path","User") +} else { + Write-Host "Chocolatey is already installed." -ForegroundColor Green +} + +Write-Host "" +Write-Host "Checking for Hugo..." -ForegroundColor Yellow +$hugoPath = Get-Command hugo -ErrorAction SilentlyContinue +if (-not $hugoPath) { + Write-Host "Hugo not found. Proceeding with installation." -ForegroundColor Cyan + Write-Host "Installing Hugo (extended version)... This may take a moment." -ForegroundColor Cyan + choco install hugo-extended -y + if ($LASTEXITCODE -ne 0) { + Write-Error "Hugo installation failed. Please check your Chocolatey setup." + Read-Host "Press Enter to exit" + exit 1 + } + Write-Host "Hugo installed successfully." -ForegroundColor Green +} else { + Write-Host "Hugo is already installed." -ForegroundColor Green +} + +Write-Host "" +Write-Host "Changing directory to Hugo project path: $hugoProjectPath" -ForegroundColor Yellow +Set-Location -Path $hugoProjectPath + +Write-Host "All dependencies are met. Starting Hugo development server..." -ForegroundColor Yellow +Write-Host "Your site will be available at http://localhost:1313/" -ForegroundColor Cyan +Write-Host "Press Ctrl+C in this window to stop the server." -ForegroundColor Cyan +Write-Host "" + +hugo server -D + +Read-Host "Server stopped. Press Enter to exit." diff --git a/Docs/StartDocsWebServerASLM.bat b/Docs/StartDocsWebServerASLM.bat new file mode 100644 index 0000000..46605c6 --- /dev/null +++ b/Docs/StartDocsWebServerASLM.bat @@ -0,0 +1,14 @@ +@echo off +TITLE Start ASLM Docs Web Server + +:: ================================================================= +:: Batch Script: StartDocsWebServerASLM.bat +:: +:: Launches DocsWebServerASLM.ps1 to start the Hugo documentation +:: development server for ASLM. +:: ================================================================= + +ECHO Launching the ASLM documentation web server... +ECHO. + +powershell.exe -ExecutionPolicy Bypass -File "%~dp0DocsWebServerASLM.ps1" diff --git a/Runtime/executors/aslm_chat_executor.py b/Runtime/executors/aslm_chat_executor.py new file mode 100644 index 0000000..2f79098 --- /dev/null +++ b/Runtime/executors/aslm_chat_executor.py @@ -0,0 +1,59 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +from __future__ import annotations + +import logging +from typing import Callable + +from Apps.UI.chat_backend import build_chat_generate_payload, partition_tool_server_ids +from Services import aslm_chat_client, aslm_chat_stream +from Runtime.types import RunSpec + +logger = logging.getLogger(__name__) + + +# Real executor that streams one generation from ASLM-Chat into the event log. +# It reuses the existing clean generation plumbing (chat_backend + Services) and +# never imports the large views module. +def execute_aslm_chat(spec: RunSpec, emit: Callable[[str, dict], object], should_abort: Callable[[], bool]) -> None: + resolved = spec.resolved + engine = resolved.engine.engine + model = resolved.model + session_id = spec.chat_id or "run" + + # Split the requested tools into local Code tools and Chat-hosted tools. + local_tool_ids, chat_tool_ids = partition_tool_server_ids(engine, model, list(resolved.tool_server_ids)) + + payload = build_chat_generate_payload( + engine=engine, + model_name=model, + llm_messages=list(spec.messages), + system_prompt=spec.system_prompt, + session_id=session_id, + clean_options=dict(resolved.options), + local_tool_server_ids=local_tool_ids, + chat_tool_server_ids=chat_tool_ids, + ) + + accumulator = aslm_chat_stream.ChatStreamAccumulator() + last_visible = "" + + # Stream chunks, emitting visible-text deltas as token events. + for chunk in aslm_chat_client.iter_generate_stream(payload): + if should_abort(): + return + + accumulator.append(chunk) + visible, _thinking, _transcript = accumulator.snapshot() + + if visible == last_visible: + continue + if visible.startswith(last_visible): + emit("token", {"text": visible[len(last_visible):]}) + else: + # The parsed visible text was rewritten; resend it as a replacement. + emit("token", {"text": visible, "replace": True}) + last_visible = visible + + visible, thinking, transcript = accumulator.snapshot() + emit("message", {"text": visible, "thinking": thinking, "transcript": transcript}) diff --git a/Runtime/executors/lms_direct_executor.py b/Runtime/executors/lms_direct_executor.py new file mode 100644 index 0000000..1689e9b --- /dev/null +++ b/Runtime/executors/lms_direct_executor.py @@ -0,0 +1,133 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +from __future__ import annotations + +import json +import logging +import urllib.error +import urllib.request +from typing import Callable + +from Runtime.types import RunSpec + +logger = logging.getLogger(__name__) + +_COMPLETIONS_PATH = "/v1/chat/completions" +_MODELS_PATH = "/v1/models" + + +# Normalize one raw engine base_url (may lack scheme) to a full http:// URL. +def _base_http_url(raw: str) -> str: + raw = str(raw or "").strip() + if not raw: + raw = "127.0.0.1:1234" + if "://" not in raw: + raw = "http://" + raw + return raw.rstrip("/") + + +# Parse one SSE "data: ..." line into a dict; return None for control lines or [DONE]. +def _parse_sse_line(line: str) -> dict | None: + line = line.strip() + if not line.startswith("data:"): + return None + payload = line[5:].strip() + if payload == "[DONE]": + return None + try: + parsed = json.loads(payload) + return parsed if isinstance(parsed, dict) else None + except json.JSONDecodeError: + logger.debug("Unparseable SSE payload: %r", payload[:120]) + return None + + +# Return the list of model ids currently loaded in a local OpenAI-compat provider. +def list_models(base_url: str) -> list[str]: + url = _base_http_url(base_url) + _MODELS_PATH + req = urllib.request.Request(url, method="GET", + headers={"Accept": "application/json"}) + try: + with urllib.request.urlopen(req, timeout=10.0) as resp: + payload = json.loads(resp.read().decode("utf-8", errors="replace")) + except Exception as exc: + logger.debug("list_models failed for %s: %s", url, exc) + return [] + data = payload.get("data") or [] + return [str(entry.get("id") or "") for entry in data if entry.get("id")] + + +# Stream one generation from an OpenAI-compatible /v1/chat/completions endpoint. +# Emits "token" events as deltas arrive and a final "message" event on completion. +def execute_lms_direct( + spec: RunSpec, + emit: Callable[[str, dict], object], + should_abort: Callable[[], bool], +) -> None: + resolved = spec.resolved + base_url = _base_http_url(resolved.engine.base_url) + model = resolved.model + url = base_url + _COMPLETIONS_PATH + timeout = resolved.limits.request_timeout_s + + # Prepend the system prompt as a system message when one is provided. + messages = list(spec.messages) + if spec.system_prompt: + messages = [{"role": "system", "content": spec.system_prompt}] + messages + + body = json.dumps( + {"model": model, "messages": messages, "stream": True}, + ensure_ascii=False, + ).encode("utf-8") + + req = urllib.request.Request( + url, + data=body, + method="POST", + headers={ + "Content-Type": "application/json", + "Accept": "text/event-stream", + }, + ) + + logger.debug("execute_lms_direct → POST %s model=%r", url, model) + + accumulated = "" + buffer = "" + + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + while True: + if should_abort(): + logger.debug("execute_lms_direct: abort requested, stopping stream") + return + + chunk = resp.read(1024) + if not chunk: + break + + buffer += chunk.decode("utf-8", errors="replace") + + # Consume complete SSE lines from the buffer. + while "\n" in buffer: + line, buffer = buffer.split("\n", 1) + parsed = _parse_sse_line(line) + if parsed is None: + continue + + choices = parsed.get("choices") or [] + if not choices: + continue + + delta = (choices[0].get("delta") or {}) + content = delta.get("content") + if not content: + continue + + emit("token", {"text": content}) + accumulated += content + + except urllib.error.URLError as exc: + raise RuntimeError(f"LMS connection failed ({url}): {exc}") from exc + + emit("message", {"text": accumulated}) diff --git a/Tools/file_system/fs_tools.py b/Tools/file_system/fs_tools.py new file mode 100644 index 0000000..ef79cd3 --- /dev/null +++ b/Tools/file_system/fs_tools.py @@ -0,0 +1,145 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +from __future__ import annotations + +from typing import Any + +from Tools.file_system.responses import ToolError, success_response +from Tools.file_system.workspace_paths import resolve_in_workspace, to_relative, workspace_root + +# Cap on how many bytes one read_file call returns before truncating. +_MAX_READ_BYTES = 256 * 1024 + +# Cap on how many directory entries one list_dir call returns. +_MAX_LIST_ENTRIES = 1000 + + +# Read a UTF-8 text file from the workspace, optionally a 1-based line slice. +def read_file(path: str, start_line: int | None = None, end_line: int | None = None) -> dict[str, Any]: + target = resolve_in_workspace(path) + if not target.exists(): + raise ToolError("not_found", f"File '{path}' does not exist.") + if target.is_dir(): + raise ToolError("is_a_directory", f"Path '{path}' is a directory, not a file.") + + raw = target.read_bytes() + truncated = len(raw) > _MAX_READ_BYTES + text = raw[:_MAX_READ_BYTES].decode("utf-8", errors="replace") + + lines = text.split("\n") + total_lines = len(lines) + + # Apply an optional 1-based inclusive line window over the decoded text. + if start_line is not None or end_line is not None: + lo = max(1, int(start_line or 1)) + hi = min(total_lines, int(end_line or total_lines)) + if lo > hi: + raise ToolError("invalid_arguments", f"Invalid line range {lo}:{hi}.") + text = "\n".join(lines[lo - 1:hi]) + else: + lo = 1 + hi = total_lines + + return success_response( + "read_file", + { + "path": to_relative(target), + "content": text, + "start_line": lo, + "end_line": hi, + "total_lines": total_lines, + "size_bytes": len(raw), + }, + warnings=["File truncated at read limit."] if truncated else None, + truncated=truncated, + ) + + +# Create a new UTF-8 text file or fully overwrite an existing one. +def write_file(path: str, content: str) -> dict[str, Any]: + target = resolve_in_workspace(path) + if target.is_dir(): + raise ToolError("is_a_directory", f"Path '{path}' is a directory.") + + existed = target.exists() + target.parent.mkdir(parents=True, exist_ok=True) + data = str(content or "") + target.write_text(data, encoding="utf-8", newline="") + + return success_response( + "write_file", + { + "path": to_relative(target), + "created": not existed, + "size_bytes": len(data.encode("utf-8")), + "lines": data.count("\n") + 1 if data else 0, + }, + ) + + +# Replace an exact substring in a file; fail on missing or ambiguous matches. +def edit_file(path: str, old_str: str, new_str: str, replace_all: bool = False) -> dict[str, Any]: + target = resolve_in_workspace(path) + if not target.exists(): + raise ToolError("not_found", f"File '{path}' does not exist.") + if target.is_dir(): + raise ToolError("is_a_directory", f"Path '{path}' is a directory.") + + text = target.read_text(encoding="utf-8", errors="replace") + old = str(old_str or "") + if not old: + raise ToolError("invalid_arguments", "old_str must be non-empty.") + + count = text.count(old) + if count == 0: + raise ToolError("no_match", f"old_str was not found in '{path}'.") + if count > 1 and not replace_all: + raise ToolError( + "ambiguous_match", + f"old_str matches {count} locations in '{path}'; pass replace_all=true or add more context.", + ) + + updated = text.replace(old, str(new_str or "")) if replace_all else text.replace(old, str(new_str or ""), 1) + target.write_text(updated, encoding="utf-8", newline="") + + return success_response( + "edit_file", + { + "path": to_relative(target), + "replacements": count if replace_all else 1, + "size_bytes": len(updated.encode("utf-8")), + }, + ) + + +# List entries under a workspace directory, optionally walking recursively. +def list_dir(path: str = ".", recursive: bool = False) -> dict[str, Any]: + target = resolve_in_workspace(path) if path not in {"", "."} else workspace_root() + if not target.exists(): + raise ToolError("not_found", f"Directory '{path}' does not exist.") + if not target.is_dir(): + raise ToolError("not_a_directory", f"Path '{path}' is not a directory.") + + entries: list[dict[str, Any]] = [] + truncated = False + + # Walk either one level or the whole subtree, capped at the entry limit. + iterator = target.rglob("*") if recursive else target.iterdir() + for item in sorted(iterator, key=lambda p: p.as_posix()): + if len(entries) >= _MAX_LIST_ENTRIES: + truncated = True + break + entries.append( + { + "path": to_relative(item), + "type": "dir" if item.is_dir() else "file", + "size_bytes": item.stat().st_size if item.is_file() else None, + } + ) + + return success_response( + "list_dir", + {"path": to_relative(target), "entries": entries, "count": len(entries)}, + warnings=["Directory listing truncated."] if truncated else None, + truncated=truncated, + ) diff --git a/Tools/file_system/registry.py b/Tools/file_system/registry.py new file mode 100644 index 0000000..b13bd8e --- /dev/null +++ b/Tools/file_system/registry.py @@ -0,0 +1,139 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +from __future__ import annotations + +from typing import Any, Callable + +from Tools.file_system import fs_tools, shell_tool +from Tools.file_system.responses import error_response, exception_response + +# Tool definitions in a neutral schema (id/name/description/parameters). +# parameters follow JSON Schema, ready to project into any provider format. +TOOLS: list[dict[str, Any]] = [ + { + "id": "read_file", + "name": "Read File", + "description": ( + "Read a UTF-8 text file from the workspace. " + "Pass start_line/end_line (1-based, inclusive) to read only a slice. " + "Returns content, total_lines, and size_bytes." + ), + "parameters": { + "type": "object", + "properties": { + "path": {"type": "string"}, + "start_line": {"type": "integer"}, + "end_line": {"type": "integer"}, + }, + "required": ["path"], + }, + }, + { + "id": "write_file", + "name": "Write File", + "description": ( + "Create a new UTF-8 text file or fully overwrite an existing one. " + "Use relative paths inside the workspace. " + "Use edit_file for small surgical changes instead of rewriting." + ), + "parameters": { + "type": "object", + "properties": { + "path": {"type": "string"}, + "content": {"type": "string"}, + }, + "required": ["path", "content"], + }, + }, + { + "id": "edit_file", + "name": "Edit File", + "description": ( + "Replace an exact substring old_str with new_str in a file. " + "Fails if old_str is missing or matches multiple times unless replace_all=true." + ), + "parameters": { + "type": "object", + "properties": { + "path": {"type": "string"}, + "old_str": {"type": "string"}, + "new_str": {"type": "string"}, + "replace_all": {"type": "boolean", "default": False}, + }, + "required": ["path", "old_str", "new_str"], + }, + }, + { + "id": "list_dir", + "name": "List Directory", + "description": ( + "List files and directories under a workspace path. " + "Pass recursive=true to walk the whole subtree." + ), + "parameters": { + "type": "object", + "properties": { + "path": {"type": "string", "default": "."}, + "recursive": {"type": "boolean", "default": False}, + }, + "required": [], + }, + }, + { + "id": "run_command", + "name": "Run Command", + "description": ( + "Run a shell command inside the workspace and capture its output. " + "Best for builds, tests, git, installs, and inspection. " + "Returns exit_code, stdout, stderr, and elapsed_ms. " + "Raise timeout_s for long-running commands." + ), + "parameters": { + "type": "object", + "properties": { + "command": {"type": "string"}, + "cwd": {"type": "string", "default": "."}, + "timeout_s": {"type": "integer", "default": 60}, + }, + "required": ["command"], + }, + }, +] + + +# Dispatch table mapping each tool id to its implementing callable. +_HANDLERS: dict[str, Callable[..., dict[str, Any]]] = { + "read_file": fs_tools.read_file, + "write_file": fs_tools.write_file, + "edit_file": fs_tools.edit_file, + "list_dir": fs_tools.list_dir, + "run_command": shell_tool.run_command, +} + + +# Execute one tool by id with keyword arguments, wrapping every failure. +def handle_tool(tool_id: str, arguments: dict[str, Any] | None = None) -> dict[str, Any]: + handler = _HANDLERS.get(tool_id) + if handler is None: + return error_response(tool_id, "unknown_tool", f"Unknown tool: {tool_id}") + try: + return handler(**(arguments or {})) + except TypeError as exc: + return error_response(tool_id, "invalid_arguments", str(exc)) + except Exception as exc: + return exception_response(tool_id, exc) + + +# Return the tool catalog projected into the OpenAI "tools" wire format. +def openai_tool_schemas() -> list[dict[str, Any]]: + return [ + { + "type": "function", + "function": { + "name": tool["id"], + "description": tool["description"], + "parameters": tool["parameters"], + }, + } + for tool in TOOLS + ] diff --git a/Tools/file_system/responses.py b/Tools/file_system/responses.py new file mode 100644 index 0000000..166621d --- /dev/null +++ b/Tools/file_system/responses.py @@ -0,0 +1,72 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + + +# Structured error raised by tool helpers, carrying a typed code. +@dataclass +class ToolError(Exception): + error_type: str + message: str + result: dict[str, Any] | None = None + + # Return the human-readable message for this error. + def __str__(self) -> str: + return self.message + + +# Wrap a successful tool result in the shared tool envelope. +def success_response( + tool: str, + result: dict[str, Any] | None = None, + *, + warnings: list[str] | None = None, + truncated: bool = False, +) -> dict[str, Any]: + return { + "ok": True, + "tool": tool, + "result": result or {}, + "error": None, + "warnings": list(warnings or []), + "truncated": bool(truncated), + } + + +# Wrap a failed tool result in the shared tool envelope. +def error_response( + tool: str, + error_type: str, + message: str, + *, + result: dict[str, Any] | None = None, + warnings: list[str] | None = None, +) -> dict[str, Any]: + return { + "ok": False, + "tool": tool, + "result": result or {}, + "error": {"type": error_type, "message": message}, + "warnings": list(warnings or []), + "truncated": False, + } + + +# Map a raised Python exception into a typed tool error envelope. +def exception_response(tool: str, exc: Exception) -> dict[str, Any]: + if isinstance(exc, ToolError): + return error_response(tool, exc.error_type, exc.message, result=exc.result) + if isinstance(exc, FileNotFoundError): + return error_response(tool, "not_found", str(exc)) + if isinstance(exc, NotADirectoryError): + return error_response(tool, "not_a_directory", str(exc)) + if isinstance(exc, IsADirectoryError): + return error_response(tool, "is_a_directory", str(exc)) + if isinstance(exc, PermissionError): + return error_response(tool, "permission_denied", str(exc)) + if isinstance(exc, ValueError): + return error_response(tool, "invalid_arguments", str(exc)) + return error_response(tool, "internal_error", str(exc)) diff --git a/Tools/file_system/shell_tool.py b/Tools/file_system/shell_tool.py new file mode 100644 index 0000000..8a6412a --- /dev/null +++ b/Tools/file_system/shell_tool.py @@ -0,0 +1,135 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +from __future__ import annotations + +import os +import shutil +import subprocess +import time +from typing import Any + +from Tools.file_system.responses import ToolError, error_response, success_response +from Tools.file_system.workspace_paths import resolve_in_workspace, to_relative, workspace_root + +# Default and maximum command timeouts in seconds. +_DEFAULT_TIMEOUT_S = 60 +_MAX_TIMEOUT_S = 600 + +# Cap on captured stdout/stderr size before an inline truncation marker is added. +_MAX_OUTPUT_BYTES = 64 * 1024 + +# Cached resolved shell so the system probe runs only once per process. +_SHELL_CACHE: tuple[list[str], str] | None = None + + +# Probe the host system and pick the native interactive shell. +# Windows prefers PowerShell 7 (pwsh), then Windows PowerShell, never cmd.exe; +# POSIX prefers bash, then falls back to sh. +def _resolve_shell() -> tuple[list[str], str]: + global _SHELL_CACHE + if _SHELL_CACHE is not None: + return _SHELL_CACHE + + if os.name == "nt": + pwsh = shutil.which("pwsh") + if pwsh: + # Force UTF-8 on the output pipe so captured text decodes cleanly. + prefix = [pwsh, "-NoProfile", "-NonInteractive", "-Command", + "$OutputEncoding=[Console]::OutputEncoding=[Text.UTF8Encoding]::new();"] + resolved = (prefix, "pwsh") + else: + powershell = shutil.which("powershell") or "powershell" + prefix = [powershell, "-NoProfile", "-NonInteractive", "-Command", + "[Console]::OutputEncoding=[Text.UTF8Encoding]::new();"] + resolved = (prefix, "powershell") + else: + bash = shutil.which("bash") + if bash: + resolved = ([bash, "-c"], "bash") + else: + resolved = ([shutil.which("sh") or "/bin/sh", "-c"], "sh") + + _SHELL_CACHE = resolved + return resolved + + +# Build the full argv for one command under the resolved shell. +# PowerShell appends the user command after its UTF-8 bootstrap in the same -Command string. +def _build_argv(command: str) -> tuple[list[str], str]: + prefix, label = _resolve_shell() + if label in {"pwsh", "powershell"}: + argv = prefix[:-1] + [prefix[-1] + " " + command] + else: + argv = prefix + [command] + return argv, label + + +# Trim one output stream to the byte cap, returning the text and a truncated flag. +def _truncate(text: str) -> tuple[str, bool]: + encoded = text.encode("utf-8", errors="replace") + if len(encoded) <= _MAX_OUTPUT_BYTES: + return text, False + clipped = encoded[:_MAX_OUTPUT_BYTES].decode("utf-8", errors="replace") + return clipped + "\n...[output truncated]...", True + + +# Run one shell command inside the workspace and capture its result. +# Returns exit_code, stdout, stderr, elapsed_ms, and the resolved cwd. +def run_command(command: str, cwd: str = ".", timeout_s: int = _DEFAULT_TIMEOUT_S) -> dict[str, Any]: + command = str(command or "").strip() + if not command: + raise ToolError("invalid_arguments", "A non-empty command is required.") + + work_dir = workspace_root() if cwd in {"", "."} else resolve_in_workspace(cwd) + if not work_dir.is_dir(): + raise ToolError("not_a_directory", f"cwd '{cwd}' is not a directory.") + + timeout = max(1, min(int(timeout_s or _DEFAULT_TIMEOUT_S), _MAX_TIMEOUT_S)) + argv, shell_label = _build_argv(command) + started = time.monotonic() + + try: + completed = subprocess.run( + argv, + cwd=str(work_dir), + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + timeout=timeout, + ) + except subprocess.TimeoutExpired: + elapsed_ms = int((time.monotonic() - started) * 1000) + return error_response( + "run_command", + "timeout", + f"Command timed out after {timeout}s.", + result={"command": command, "cwd": to_relative(work_dir), "shell": shell_label, "elapsed_ms": elapsed_ms}, + ) + + elapsed_ms = int((time.monotonic() - started) * 1000) + stdout, trunc_out = _truncate(completed.stdout or "") + stderr, trunc_err = _truncate(completed.stderr or "") + truncated = trunc_out or trunc_err + + result = { + "command": command, + "cwd": to_relative(work_dir), + "shell": shell_label, + "exit_code": completed.returncode, + "stdout": stdout, + "stderr": stderr, + "elapsed_ms": elapsed_ms, + } + + warnings = ["Command output was truncated."] if truncated else None + if completed.returncode == 0: + return success_response("run_command", result, warnings=warnings, truncated=truncated) + + return error_response( + "run_command", + "process_error", + f"Command exited with code {completed.returncode}.", + result=result, + warnings=warnings, + ) diff --git a/Tools/file_system/workspace_paths.py b/Tools/file_system/workspace_paths.py new file mode 100644 index 0000000..b34e2cb --- /dev/null +++ b/Tools/file_system/workspace_paths.py @@ -0,0 +1,54 @@ +# Copyright NGGT.LightKeeper. All Rights Reserved. + +from __future__ import annotations + +import os +from pathlib import Path + +from Tools.file_system.responses import ToolError + +# Project root is three levels up from this file (Tools/file_system/). +_PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent + +# Environment override for the agent's sandboxed workspace root. +_WORKSPACE_ENV_KEY = "ASLM_CODE_WORKSPACE" + + +# Return the absolute workspace root the agent is allowed to touch. +# Defaults to a dedicated Workspace/ directory unless overridden by env. +def workspace_root() -> Path: + raw = (os.environ.get(_WORKSPACE_ENV_KEY) or "").strip() + root = Path(raw).expanduser() if raw else (_PROJECT_ROOT / "Workspace") + root = root.resolve() + root.mkdir(parents=True, exist_ok=True) + return root + + +# Resolve one model-supplied path against the workspace and reject any escape. +# Accepts plain relative paths; absolute paths must stay within the workspace. +def resolve_in_workspace(path: str) -> Path: + raw = str(path or "").strip() + if not raw: + raise ToolError("invalid_arguments", "A non-empty path is required.") + + root = workspace_root() + candidate = Path(raw) + if not candidate.is_absolute(): + candidate = root / candidate + + # Resolve symlinks and '..' so the final location cannot leave the root. + resolved = candidate.resolve() + if resolved != root and root not in resolved.parents: + raise ToolError( + "path_escape", + f"Path '{raw}' resolves outside the workspace root and is not allowed.", + ) + return resolved + + +# Return one absolute workspace path as a clean root-relative POSIX string. +def to_relative(path: Path) -> str: + try: + return path.resolve().relative_to(workspace_root()).as_posix() or "." + except ValueError: + return path.as_posix()