create-walle 0.9.21 → 0.9.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -5
- package/package.json +2 -2
- package/template/CLAUDE.md +2 -2
- package/template/LICENSE +1 -1
- package/template/bin/ctm-dev-cleanup.js +24 -3
- package/template/bin/ctm-launch.sh +13 -0
- package/template/bin/dev.sh +156 -18
- package/template/bin/node-bin.sh +84 -0
- package/template/bin/pin-node.sh +51 -0
- package/template/claude-task-manager/api-prompts.js +1203 -182
- package/template/claude-task-manager/api-reviews.js +109 -15
- package/template/claude-task-manager/approval-agent.js +1360 -280
- package/template/claude-task-manager/bin/restart-ctm.sh +64 -23
- package/template/claude-task-manager/bin/storage-migration-supervisor.js +338 -0
- package/template/claude-task-manager/db.js +4417 -295
- package/template/claude-task-manager/docs/app-update-refresh-protocol.md +69 -0
- package/template/claude-task-manager/docs/approval-ai-refinement.md +138 -0
- package/template/claude-task-manager/docs/approval-rescue-loop.md +74 -0
- package/template/claude-task-manager/docs/codex-operational-warning-health.md +107 -0
- package/template/claude-task-manager/docs/codex-resume-state-guard-design.md +17 -12
- package/template/claude-task-manager/docs/codex-terminal-render-controller-handoff.md +311 -0
- package/template/claude-task-manager/docs/coding-agent-hooks-architecture.md +418 -0
- package/template/claude-task-manager/docs/conversation-import-freshness.md +20 -0
- package/template/claude-task-manager/docs/google-workspace-auth-health.md +77 -0
- package/template/claude-task-manager/docs/image-paste-ux.md +13 -0
- package/template/claude-task-manager/docs/ipad-web-preview.md +88 -0
- package/template/claude-task-manager/docs/main-loop-offload-architecture.md +66 -0
- package/template/claude-task-manager/docs/microsoft-dev-tunnel-phone-access-design.md +274 -519
- package/template/claude-task-manager/docs/mobile-live-streaming.md +27 -5
- package/template/claude-task-manager/docs/mobile-remote-submission-lifecycle.md +69 -0
- package/template/claude-task-manager/docs/phone-access-design.md +53 -15
- package/template/claude-task-manager/docs/phone-passkey-identity.md +122 -0
- package/template/claude-task-manager/docs/phone-setup.md +3 -0
- package/template/claude-task-manager/docs/prompt-editing-tree-design.md +25 -1
- package/template/claude-task-manager/docs/remote-desktop-access-design.md +268 -0
- package/template/claude-task-manager/docs/restart-lifecycle-architecture.md +95 -0
- package/template/claude-task-manager/docs/runtime-work-control-plane.md +53 -0
- package/template/claude-task-manager/docs/session-interactive-wait-surfaces.md +38 -0
- package/template/claude-task-manager/docs/session-needs-you-dismissal.md +84 -0
- package/template/claude-task-manager/docs/session-render-state-management-design.md +91 -3
- package/template/claude-task-manager/docs/session-standup-command-center-design.md +25 -1
- package/template/claude-task-manager/docs/session-title-authority.md +32 -0
- package/template/claude-task-manager/docs/session-workspace-binding.md +33 -0
- package/template/claude-task-manager/docs/skill-intent-resolution-design.md +72 -0
- package/template/claude-task-manager/docs/walle-mcp-supervisor-health.md +86 -0
- package/template/claude-task-manager/docs/walle-relay-phone-access-design.md +24 -15
- package/template/claude-task-manager/docs/walle-session-history-hydration.md +114 -0
- package/template/claude-task-manager/docs/walle-session-input-queue.md +104 -0
- package/template/claude-task-manager/docs/walle-session-model-catalog.md +90 -0
- package/template/claude-task-manager/docs/walle-session-model-preferences.md +15 -6
- package/template/claude-task-manager/git-utils.js +897 -27
- package/template/claude-task-manager/lib/agent-capabilities.js +33 -0
- package/template/claude-task-manager/lib/agent-cli-cache.js +37 -7
- package/template/claude-task-manager/lib/agent-hooks-installer.js +26 -2
- package/template/claude-task-manager/lib/agent-presets.js +17 -1
- package/template/claude-task-manager/lib/all-sessions-query.js +108 -0
- package/template/claude-task-manager/lib/approval-ai-refinement.js +488 -0
- package/template/claude-task-manager/lib/approval-self-adapt.js +168 -0
- package/template/claude-task-manager/lib/async-semaphore.js +44 -0
- package/template/claude-task-manager/lib/auth-context.js +5 -0
- package/template/claude-task-manager/lib/auth-rate-limit.js +47 -4
- package/template/claude-task-manager/lib/auth-rules.js +29 -2
- package/template/claude-task-manager/lib/auto-approval-verifier.js +129 -16
- package/template/claude-task-manager/lib/background-llm.js +144 -17
- package/template/claude-task-manager/lib/branch-inventory.js +212 -0
- package/template/claude-task-manager/lib/claude-desktop-sessions.js +15 -3
- package/template/claude-task-manager/lib/coalesce-sync-frames.js +151 -0
- package/template/claude-task-manager/lib/codex-launch-health.js +762 -0
- package/template/claude-task-manager/lib/codex-transcript-pager.js +51 -0
- package/template/claude-task-manager/lib/codex-zst.js +124 -0
- package/template/claude-task-manager/lib/coding-agent-models.js +233 -30
- package/template/claude-task-manager/lib/connection-health.js +232 -0
- package/template/claude-task-manager/lib/conversation-blob-parser.js +42 -0
- package/template/claude-task-manager/lib/conversation-tail-merge.js +89 -26
- package/template/claude-task-manager/lib/ctm-session-context-api.js +39 -10
- package/template/claude-task-manager/lib/cursor-conversation-store.js +354 -0
- package/template/claude-task-manager/lib/db-owner-worker-client.js +315 -0
- package/template/claude-task-manager/lib/document-review.js +141 -6
- package/template/claude-task-manager/lib/escalation-review.js +152 -0
- package/template/claude-task-manager/lib/graceful-shutdown.js +159 -0
- package/template/claude-task-manager/lib/headless-term-service.js +678 -0
- package/template/claude-task-manager/lib/heavy-worker-fallback.js +38 -0
- package/template/claude-task-manager/lib/jsonl-conversation-parser.js +542 -0
- package/template/claude-task-manager/lib/jsonl-range-reader.js +112 -0
- package/template/claude-task-manager/lib/main-db-census.js +216 -0
- package/template/claude-task-manager/lib/message-pagination.js +106 -4
- package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +750 -26
- package/template/claude-task-manager/lib/mobile-auth-api.js +274 -7
- package/template/claude-task-manager/lib/mobile-auth-store.js +592 -10
- package/template/claude-task-manager/lib/mobile-notification-dispatcher.js +15 -0
- package/template/claude-task-manager/lib/model-overview-brain-fallback.js +311 -0
- package/template/claude-task-manager/lib/model-overview-cache.js +141 -0
- package/template/claude-task-manager/lib/models-health-routing-notice.js +126 -0
- package/template/claude-task-manager/lib/node-pin-guard.js +93 -0
- package/template/claude-task-manager/lib/perf-tracker.js +242 -6
- package/template/claude-task-manager/lib/permission-match.js +76 -0
- package/template/claude-task-manager/lib/permission-sync.js +133 -20
- package/template/claude-task-manager/lib/process-title.js +35 -0
- package/template/claude-task-manager/lib/prompt-executions-query.js +25 -0
- package/template/claude-task-manager/lib/prompt-index-disk-cache.js +44 -0
- package/template/claude-task-manager/lib/prompt-intent.js +132 -0
- package/template/claude-task-manager/lib/provider-user-context.js +34 -0
- package/template/claude-task-manager/lib/read-pool-client.js +313 -0
- package/template/claude-task-manager/lib/readpool-breaker.js +31 -0
- package/template/claude-task-manager/lib/recent-sessions-breaker.js +12 -0
- package/template/claude-task-manager/lib/remote-feedback-client.js +72 -0
- package/template/claude-task-manager/lib/remote-relay-protocol.js +37 -4
- package/template/claude-task-manager/lib/remote-relay-store.js +159 -0
- package/template/claude-task-manager/lib/remote-submission-observer.js +278 -0
- package/template/claude-task-manager/lib/restart-guard.js +109 -0
- package/template/claude-task-manager/lib/restore-interruption-detector.js +439 -0
- package/template/claude-task-manager/lib/restore-policy.js +13 -0
- package/template/claude-task-manager/lib/restore-resume-batch.js +74 -0
- package/template/claude-task-manager/lib/restore-runtime.js +68 -0
- package/template/claude-task-manager/lib/restore-storm.js +34 -0
- package/template/claude-task-manager/lib/resume-cwd.js +36 -0
- package/template/claude-task-manager/lib/resume-preflight.js +313 -0
- package/template/claude-task-manager/lib/runtime-work-registry.js +444 -0
- package/template/claude-task-manager/lib/sanitize-openai-auth.js +31 -0
- package/template/claude-task-manager/lib/scheduler.js +21 -1
- package/template/claude-task-manager/lib/scrollback-snapshot-store.js +159 -0
- package/template/claude-task-manager/lib/serial-task-queue.js +64 -0
- package/template/claude-task-manager/lib/server-listeners.js +239 -0
- package/template/claude-task-manager/lib/session-capture.js +42 -7
- package/template/claude-task-manager/lib/session-content-backfill.js +131 -0
- package/template/claude-task-manager/lib/session-history.js +388 -43
- package/template/claude-task-manager/lib/session-host-manager.js +287 -0
- package/template/claude-task-manager/lib/session-image-refs.js +209 -0
- package/template/claude-task-manager/lib/session-jobs.js +399 -59
- package/template/claude-task-manager/lib/session-prompt-index.js +137 -0
- package/template/claude-task-manager/lib/session-restore.js +53 -0
- package/template/claude-task-manager/lib/session-standup.js +123 -23
- package/template/claude-task-manager/lib/session-state-bus.js +14 -0
- package/template/claude-task-manager/lib/session-stream.js +64 -16
- package/template/claude-task-manager/lib/session-timeline-summary.js +260 -0
- package/template/claude-task-manager/lib/session-token-usage.js +494 -0
- package/template/claude-task-manager/lib/session-workspace-binding.js +356 -0
- package/template/claude-task-manager/lib/setup-network-config.js +9 -0
- package/template/claude-task-manager/lib/size-cap.js +45 -0
- package/template/claude-task-manager/lib/size-cap.test.js +62 -0
- package/template/claude-task-manager/lib/skill-autocomplete.js +180 -1
- package/template/claude-task-manager/lib/skill-intent-resolver.js +304 -0
- package/template/claude-task-manager/lib/sqlite-driver.js +19 -3
- package/template/claude-task-manager/lib/standup-attention.js +7 -3
- package/template/claude-task-manager/lib/status-authority.js +39 -0
- package/template/claude-task-manager/lib/status-hooks.js +4 -0
- package/template/claude-task-manager/lib/storage-migration.js +235 -0
- package/template/claude-task-manager/lib/structured-capture.js +298 -0
- package/template/claude-task-manager/lib/sync-io-census.js +163 -0
- package/template/claude-task-manager/lib/tailscale-setup.js +6 -0
- package/template/claude-task-manager/lib/terminal-activity-evidence.js +33 -0
- package/template/claude-task-manager/lib/terminal-choice.js +364 -0
- package/template/claude-task-manager/lib/terminal-control-sanitize.js +17 -0
- package/template/claude-task-manager/lib/terminal-fingerprint.js +48 -0
- package/template/claude-task-manager/lib/terminal-output-flush.js +84 -0
- package/template/claude-task-manager/lib/timeline-order.js +122 -0
- package/template/claude-task-manager/lib/transcript-store.js +348 -43
- package/template/claude-task-manager/lib/transport-security.js +84 -1
- package/template/claude-task-manager/lib/wait-state.js +184 -0
- package/template/claude-task-manager/lib/walle-client.js +47 -5
- package/template/claude-task-manager/lib/walle-ctm-history.js +564 -4
- package/template/claude-task-manager/lib/walle-external-actions.js +135 -16
- package/template/claude-task-manager/lib/walle-history-hydration.js +46 -0
- package/template/claude-task-manager/lib/walle-native-health.js +403 -0
- package/template/claude-task-manager/lib/walle-repair.js +701 -0
- package/template/claude-task-manager/lib/walle-session-cache.js +109 -0
- package/template/claude-task-manager/lib/walle-session-context.js +57 -21
- package/template/claude-task-manager/lib/walle-session-model-catalog.js +34 -0
- package/template/claude-task-manager/lib/walle-supervisor.js +539 -63
- package/template/claude-task-manager/lib/walle-transcript.js +52 -0
- package/template/claude-task-manager/lib/worktree-active-sync.js +11 -7
- package/template/claude-task-manager/lib/worktree-cwd.js +32 -1
- package/template/claude-task-manager/package.json +1 -1
- package/template/claude-task-manager/prompt-harvest.js +89 -66
- package/template/claude-task-manager/providers/claude-code.js +51 -3
- package/template/claude-task-manager/providers/cursor.js +140 -45
- package/template/claude-task-manager/public/css/reviews.css +551 -61
- package/template/claude-task-manager/public/css/setup.css +191 -0
- package/template/claude-task-manager/public/css/walle-session.css +865 -10
- package/template/claude-task-manager/public/css/walle.css +154 -0
- package/template/claude-task-manager/public/designs/ai-providers-consolidation-v2.html +830 -0
- package/template/claude-task-manager/public/index.html +18516 -2058
- package/template/claude-task-manager/public/ipad.html +363 -0
- package/template/claude-task-manager/public/js/document-review-links.js +301 -0
- package/template/claude-task-manager/public/js/image-normalize.js +69 -36
- package/template/claude-task-manager/public/js/message-renderer.js +1265 -77
- package/template/claude-task-manager/public/js/prompts.js +66 -29
- package/template/claude-task-manager/public/js/reviews.js +901 -133
- package/template/claude-task-manager/public/js/session-activity-utils.js +11 -1
- package/template/claude-task-manager/public/js/session-search-utils.js +94 -10
- package/template/claude-task-manager/public/js/session-status-precedence.js +23 -5
- package/template/claude-task-manager/public/js/setup.js +1273 -176
- package/template/claude-task-manager/public/js/stream-view.js +691 -73
- package/template/claude-task-manager/public/js/terminal-reconciler.js +210 -0
- package/template/claude-task-manager/public/js/walle-session.js +2455 -158
- package/template/claude-task-manager/public/js/walle.js +455 -28
- package/template/claude-task-manager/public/m/app.css +2909 -262
- package/template/claude-task-manager/public/m/app.js +6601 -398
- package/template/claude-task-manager/public/m/claim.html +224 -17
- package/template/claude-task-manager/public/m/index.html +117 -21
- package/template/claude-task-manager/public/m/sw.js +3 -1
- package/template/claude-task-manager/public/manifest.json +2 -2
- package/template/claude-task-manager/public/prompts.html +30 -14
- package/template/claude-task-manager/queue-engine.js +507 -28
- package/template/claude-task-manager/scripts/repair-claude-session-images.js +27 -8
- package/template/claude-task-manager/server.js +14341 -2197
- package/template/claude-task-manager/session-integrity.js +160 -18
- package/template/claude-task-manager/session-search-ranking.js +1 -0
- package/template/claude-task-manager/session-utils.js +25 -5
- package/template/claude-task-manager/workers/approval-blocklist.js +96 -6
- package/template/claude-task-manager/workers/approval-widget-validator.js +14 -8
- package/template/claude-task-manager/workers/conversation-import-worker.js +11 -50
- package/template/claude-task-manager/workers/db-owner-worker.js +386 -0
- package/template/claude-task-manager/workers/harvest-worker.js +9 -55
- package/template/claude-task-manager/workers/headless-term-worker.js +9 -530
- package/template/claude-task-manager/workers/read-pool-worker.js +387 -0
- package/template/claude-task-manager/workers/scrollback-worker.js +11 -72
- package/template/claude-task-manager/workers/session-host-process.js +146 -0
- package/template/claude-task-manager/workers/session-integrity-worker.js +10 -54
- package/template/claude-task-manager/workers/state-detectors/base.js +18 -1
- package/template/claude-task-manager/workers/state-detectors/claude-code.js +182 -9
- package/template/claude-task-manager/workers/state-detectors/codex.js +150 -2
- package/template/claude-task-manager/workers/state-detectors/cursor.js +127 -0
- package/template/claude-task-manager/workers/state-detectors/gemini.js +21 -0
- package/template/claude-task-manager/workers/state-detectors/index.js +29 -0
- package/template/claude-task-manager/workers/state-detectors/opencode.js +103 -0
- package/template/docs/design/markdown-review-pane.md +206 -0
- package/template/docs/designs/2026-05-17-portkey-gateway-provider-ux.md +129 -38
- package/template/docs/designs/2026-05-20-mobile-worktree-finish-command.md +27 -0
- package/template/docs/designs/2026-05-22-ai-configuration-consolidation.md +248 -0
- package/template/docs/designs/ai-configuration-consolidation-mock.html +812 -0
- package/template/docs/private-memory-and-pii-policy.md +69 -0
- package/template/package.json +2 -1
- package/template/scripts/check-private-data.js +201 -0
- package/template/shared/sqlite-owner-guard.js +30 -0
- package/template/shared/sqlite-owner-write-queue.js +225 -0
- package/template/shared/sqlite-storage-policy.js +111 -0
- package/template/shared/sqlite-write-lock.js +428 -0
- package/template/wall-e/agent-runners/claude-code.js +5 -0
- package/template/wall-e/agent.js +166 -22
- package/template/wall-e/api-walle.js +524 -70
- package/template/wall-e/auth/provider-flows.js +11 -1
- package/template/wall-e/bin/walle-mcp-stdio.js +341 -17
- package/template/wall-e/brain.js +1614 -141
- package/template/wall-e/chat/attachment-blocks.js +96 -0
- package/template/wall-e/chat/attachments.js +2 -1
- package/template/wall-e/chat/capability-resolver.js +7 -7
- package/template/wall-e/chat/context-messages.js +28 -0
- package/template/wall-e/chat/conversation-frame.js +630 -0
- package/template/wall-e/chat/provider-messages.js +125 -0
- package/template/wall-e/chat.js +1002 -233
- package/template/wall-e/coding/acceptance-contract.js +170 -0
- package/template/wall-e/coding/acp-adapter.js +1 -1
- package/template/wall-e/coding/agent-catalog.js +3 -0
- package/template/wall-e/coding/artifact-store.js +93 -0
- package/template/wall-e/coding/capability-router.js +120 -0
- package/template/wall-e/coding/coding-run-controller.js +423 -0
- package/template/wall-e/coding/compaction-service.js +157 -12
- package/template/wall-e/coding/frontend-verification.js +258 -0
- package/template/wall-e/coding/lifecycle-hooks.js +75 -0
- package/template/wall-e/coding/local-preview-contract.js +157 -0
- package/template/wall-e/coding/permission-service.js +57 -13
- package/template/wall-e/coding/prompt-bundle.js +19 -1
- package/template/wall-e/coding/prompt-section-registry.js +227 -0
- package/template/wall-e/coding/provider-compat.js +15 -0
- package/template/wall-e/coding/runtime-events.js +224 -0
- package/template/wall-e/coding/runtime-mode.js +3 -0
- package/template/wall-e/coding/side-git-snapshot.js +160 -4
- package/template/wall-e/coding/snapshot-service.js +143 -1
- package/template/wall-e/coding/stream-processor.js +388 -34
- package/template/wall-e/coding/task-tool.js +141 -4
- package/template/wall-e/coding/tool-execution-controller.js +365 -0
- package/template/wall-e/coding/tool-registry.js +43 -5
- package/template/wall-e/coding/user-hooks.js +217 -0
- package/template/wall-e/coding-orchestrator.js +1330 -221
- package/template/wall-e/coding-prompts.js +20 -4
- package/template/wall-e/context/context-builder.js +15 -2
- package/template/wall-e/decision/confidence.js +1 -1
- package/template/wall-e/docs/coding-acceptance-contract.md +41 -0
- package/template/wall-e/docs/external-action-controller.md +26 -6
- package/template/wall-e/docs/telemetry-lifecycle.md +8 -2
- package/template/wall-e/embeddings.js +591 -53
- package/template/wall-e/external-action-controller.js +12 -0
- package/template/wall-e/http/auth.js +1 -0
- package/template/wall-e/http/chat-api.js +46 -11
- package/template/wall-e/http/model-admin.js +836 -34
- package/template/wall-e/lib/boot-profile.js +88 -0
- package/template/wall-e/lib/event-loop-monitor.js +93 -0
- package/template/wall-e/lib/service-health.js +194 -0
- package/template/wall-e/llm/anthropic.js +130 -5
- package/template/wall-e/llm/client.js +266 -63
- package/template/wall-e/llm/default-fallback.js +382 -0
- package/template/wall-e/llm/health.js +19 -0
- package/template/wall-e/llm/message-guard.js +78 -0
- package/template/wall-e/llm/model-catalog.js +252 -1
- package/template/wall-e/llm/openai.js +26 -4
- package/template/wall-e/llm/portkey-sync.js +654 -0
- package/template/wall-e/llm/provider-error.js +30 -2
- package/template/wall-e/llm/registry.js +5 -1
- package/template/wall-e/llm/request-compat.js +67 -0
- package/template/wall-e/loops/backfill.js +79 -23
- package/template/wall-e/loops/brain-optimize.js +67 -0
- package/template/wall-e/loops/ingest.js +25 -10
- package/template/wall-e/loops/question-digest.js +160 -0
- package/template/wall-e/loops/reflect.js +6 -4
- package/template/wall-e/loops/think.js +39 -12
- package/template/wall-e/mcp-server.js +318 -36
- package/template/wall-e/memory/ctm-context-client.js +52 -14
- package/template/wall-e/memory/ctm-operational-context.js +237 -0
- package/template/wall-e/memory/ctm-prompt-executions-client.js +128 -0
- package/template/wall-e/memory/ctm-session-context.js +111 -63
- package/template/wall-e/prompts/coding/deepseek.txt +3 -0
- package/template/wall-e/prompts/coding/gemini.txt +6 -0
- package/template/wall-e/prompts/coding/gpt.txt +6 -0
- package/template/wall-e/prompts/coding/local.txt +7 -0
- package/template/wall-e/runtime/decision-hooks.js +115 -0
- package/template/wall-e/runtime/devbox-gateway.js +82 -8
- package/template/wall-e/runtime/prompt-manifest.js +86 -0
- package/template/wall-e/runtime/tool-executor.js +269 -0
- package/template/wall-e/runtime/tool-result-envelope.js +138 -0
- package/template/wall-e/runtime/transcript-projection.js +60 -0
- package/template/wall-e/runtime/walle-runtime.js +224 -0
- package/template/wall-e/scripts/db-optimize/migrate.js +162 -0
- package/template/wall-e/scripts/db-optimize/recall-eval.js +117 -0
- package/template/wall-e/server.js +15 -0
- package/template/wall-e/session-files.js +9 -0
- package/template/wall-e/skills/_bundled/google-calendar/run.js +1 -1
- package/template/wall-e/skills/_bundled/gws-workspace/run.js +1 -1
- package/template/wall-e/skills/_bundled/slack-mentions/run.js +76 -6
- package/template/wall-e/skills/claude-code-reader.js +7 -3
- package/template/wall-e/skills/script-skill-runner.js +10 -0
- package/template/wall-e/skills/skill-planner.js +38 -0
- package/template/wall-e/tools/builtin-middleware.js +19 -9
- package/template/wall-e/tools/local-tools.js +1428 -16
- package/template/wall-e/tools/permission-checker.js +73 -5
- package/template/wall-e/tools/question-manager.js +117 -7
- package/template/wall-e/training/harvester.js +12 -28
- package/template/wall-e/training/replay.js +25 -80
- package/template/website/index.html +10 -10
- package/template/wall-e/eval/ab-test.js +0 -203
- package/template/wall-e/eval/agent-runner.js +0 -772
- package/template/wall-e/eval/agent-scorer.js +0 -461
- package/template/wall-e/eval/aggregator.js +0 -414
- package/template/wall-e/eval/allowed-test-commands.js +0 -34
- package/template/wall-e/eval/benchmark-generator.js +0 -113
- package/template/wall-e/eval/benchmarks/chat-eval.json +0 -1662
- package/template/wall-e/eval/benchmarks/chat.json +0 -82
- package/template/wall-e/eval/benchmarks/coding-agent-real.json +0 -1
- package/template/wall-e/eval/benchmarks/coding-agent.json +0 -1581
- package/template/wall-e/eval/benchmarks/coding.json +0 -122
- package/template/wall-e/eval/benchmarks/memory-retrieval.json +0 -234
- package/template/wall-e/eval/benchmarks/reasoning.json +0 -82
- package/template/wall-e/eval/benchmarks/swebench-lite-30.json +0 -212
- package/template/wall-e/eval/benchmarks.js +0 -669
- package/template/wall-e/eval/cc-replay.js +0 -719
- package/template/wall-e/eval/chat-eval.js +0 -525
- package/template/wall-e/eval/check-keys.js +0 -15
- package/template/wall-e/eval/check-providers.js +0 -42
- package/template/wall-e/eval/codex-cli-baseline.js +0 -669
- package/template/wall-e/eval/coding-agent-real.js +0 -570
- package/template/wall-e/eval/context-compactor.js +0 -251
- package/template/wall-e/eval/debug-agent003.js +0 -68
- package/template/wall-e/eval/diagnostics.js +0 -216
- package/template/wall-e/eval/eval-orchestrator.js +0 -642
- package/template/wall-e/eval/evaluate.js +0 -202
- package/template/wall-e/eval/evaluator.js +0 -373
- package/template/wall-e/eval/exporter.js +0 -212
- package/template/wall-e/eval/fixtures/express-basic/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-basic/server.js +0 -115
- package/template/wall-e/eval/fixtures/express-basic/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-buggy/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-buggy/server.js +0 -113
- package/template/wall-e/eval/fixtures/express-buggy/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-buggy-items/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-buggy-items/server.js +0 -112
- package/template/wall-e/eval/fixtures/express-buggy-items/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-buggy-search/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-buggy-search/server.js +0 -121
- package/template/wall-e/eval/fixtures/express-buggy-search/test.js +0 -83
- package/template/wall-e/eval/fixtures/express-rename-data/data.js +0 -34
- package/template/wall-e/eval/fixtures/express-rename-data/package.json +0 -9
- package/template/wall-e/eval/fixtures/express-rename-data/server.js +0 -97
- package/template/wall-e/eval/fixtures/express-rename-data/test.js +0 -88
- package/template/wall-e/eval/fixtures/express-xss/package.json +0 -12
- package/template/wall-e/eval/fixtures/express-xss/server.js +0 -90
- package/template/wall-e/eval/fixtures/express-xss/test.js +0 -67
- package/template/wall-e/eval/fixtures/express-xss/views/profile.ejs +0 -9
- package/template/wall-e/eval/fixtures/fullstack-app/config/default.js +0 -9
- package/template/wall-e/eval/fixtures/fullstack-app/config/test.js +0 -13
- package/template/wall-e/eval/fixtures/fullstack-app/package.json +0 -11
- package/template/wall-e/eval/fixtures/fullstack-app/public/css/style.css +0 -137
- package/template/wall-e/eval/fixtures/fullstack-app/public/index.html +0 -46
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/app.js +0 -121
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/auth.js +0 -71
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/items.js +0 -80
- package/template/wall-e/eval/fixtures/fullstack-app/public/js/users.js +0 -46
- package/template/wall-e/eval/fixtures/fullstack-app/public/login.html +0 -45
- package/template/wall-e/eval/fixtures/fullstack-app/public/register.html +0 -38
- package/template/wall-e/eval/fixtures/fullstack-app/scripts/migrate.js +0 -23
- package/template/wall-e/eval/fixtures/fullstack-app/scripts/seed.js +0 -46
- package/template/wall-e/eval/fixtures/fullstack-app/server/db.js +0 -99
- package/template/wall-e/eval/fixtures/fullstack-app/server/index.js +0 -94
- package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/auth.js +0 -19
- package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/logger.js +0 -19
- package/template/wall-e/eval/fixtures/fullstack-app/server/router.js +0 -50
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/auth.js +0 -69
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/health.js +0 -23
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/items.js +0 -88
- package/template/wall-e/eval/fixtures/fullstack-app/server/routes/users.js +0 -75
- package/template/wall-e/eval/fixtures/fullstack-app/server/test.js +0 -198
- package/template/wall-e/eval/fixtures/fullstack-app/server/utils/response.js +0 -34
- package/template/wall-e/eval/fixtures/fullstack-app/server/utils/validate.js +0 -26
- package/template/wall-e/eval/fixtures/fullstack-app/server.js +0 -8
- package/template/wall-e/eval/fixtures/fullstack-app/test.js +0 -12
- package/template/wall-e/eval/fixtures/monorepo-basic/package.json +0 -8
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/data.js +0 -58
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/middleware.js +0 -46
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/package.json +0 -8
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/routes.js +0 -64
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/server.js +0 -56
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/test.js +0 -116
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/commands.js +0 -61
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/index.js +0 -62
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/output.js +0 -43
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/package.json +0 -11
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/test.js +0 -44
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/formatters.js +0 -43
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/index.js +0 -12
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/package.json +0 -5
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/test.js +0 -55
- package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/validators.js +0 -29
- package/template/wall-e/eval/fixtures/monorepo-basic/test.js +0 -46
- package/template/wall-e/eval/fixtures/node-cli/index.js +0 -78
- package/template/wall-e/eval/fixtures/node-cli/package.json +0 -10
- package/template/wall-e/eval/fixtures/node-cli/test.js +0 -57
- package/template/wall-e/eval/fixtures/node-typed/package.json +0 -8
- package/template/wall-e/eval/fixtures/node-typed/src/handlers.js +0 -31
- package/template/wall-e/eval/fixtures/node-typed/src/utils.js +0 -33
- package/template/wall-e/eval/fixtures/node-typed/test.js +0 -36
- package/template/wall-e/eval/fixtures/python-flask/app.py +0 -14
- package/template/wall-e/eval/fixtures/python-flask/requirements.txt +0 -2
- package/template/wall-e/eval/fixtures/python-flask/test_app.py +0 -25
- package/template/wall-e/eval/fixtures/wall-e-subset/brain.js +0 -105
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/aggregator.js +0 -101
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/chat.json +0 -20
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/coding.json +0 -32
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks.js +0 -64
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/package.json +0 -6
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/server.js +0 -31
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/test.js +0 -18
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/utils.js +0 -34
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/runner.js +0 -104
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/scorer.js +0 -73
- package/template/wall-e/eval/fixtures/wall-e-subset/eval/test.js +0 -134
- package/template/wall-e/eval/fixtures/wall-e-subset/llm/client.js +0 -99
- package/template/wall-e/eval/fixtures/wall-e-subset/llm/providers.js +0 -63
- package/template/wall-e/eval/fixtures/wall-e-subset/llm/test.js +0 -70
- package/template/wall-e/eval/fixtures/wall-e-subset/package.json +0 -10
- package/template/wall-e/eval/fixtures/wall-e-subset/test.js +0 -86
- package/template/wall-e/eval/harvester.js +0 -685
- package/template/wall-e/eval/head-to-head.js +0 -388
- package/template/wall-e/eval/humaneval-adapter.js +0 -321
- package/template/wall-e/eval/list-models.js +0 -31
- package/template/wall-e/eval/livecodebench-adapter.js +0 -291
- package/template/wall-e/eval/mail-integration.js +0 -443
- package/template/wall-e/eval/manifest.js +0 -186
- package/template/wall-e/eval/meta-harness/adapters/coding-agent.js +0 -57
- package/template/wall-e/eval/meta-harness/bootstrap-snapshot.js +0 -149
- package/template/wall-e/eval/meta-harness/candidate-store.js +0 -117
- package/template/wall-e/eval/meta-harness/cli.js +0 -86
- package/template/wall-e/eval/meta-harness/domain-spec.js +0 -154
- package/template/wall-e/eval/meta-harness/domains/coding-agent.domain.json +0 -84
- package/template/wall-e/eval/meta-harness/examples/env-bootstrap-candidate.js +0 -29
- package/template/wall-e/eval/meta-harness/experience-store.js +0 -174
- package/template/wall-e/eval/meta-harness/frontier.js +0 -96
- package/template/wall-e/eval/meta-harness/harness-interface.js +0 -90
- package/template/wall-e/eval/meta-harness/leakage-guard.js +0 -80
- package/template/wall-e/eval/meta-harness/optimizer.js +0 -207
- package/template/wall-e/eval/meta-harness/proposer-runner.js +0 -110
- package/template/wall-e/eval/meta-harness/reporting.js +0 -58
- package/template/wall-e/eval/meta-harness/telemetry.js +0 -27
- package/template/wall-e/eval/meta-harness/validation.js +0 -81
- package/template/wall-e/eval/promoter.js +0 -228
- package/template/wall-e/eval/provider-normalizer.js +0 -33
- package/template/wall-e/eval/replay.js +0 -395
- package/template/wall-e/eval/run-agent-benchmarks.js +0 -386
- package/template/wall-e/eval/run-codex-cli-baseline.js +0 -177
- package/template/wall-e/eval/run-coding-agent-real.js +0 -187
- package/template/wall-e/eval/run-eval.js +0 -435
- package/template/wall-e/eval/run-model-comparison.js +0 -142
- package/template/wall-e/eval/session-evaluator.js +0 -187
- package/template/wall-e/eval/session-miner.js +0 -207
- package/template/wall-e/eval/session-retrieval-benchmark.js +0 -150
- package/template/wall-e/eval/session-transcripts.js +0 -509
- package/template/wall-e/eval/shadow.js +0 -161
- package/template/wall-e/eval/swebench-adapter.js +0 -345
- package/template/wall-e/eval/swebench-docker.js +0 -192
- package/template/wall-e/eval/train.py +0 -320
- package/template/wall-e/eval/trainer.js +0 -232
- package/template/wall-e/eval/weekly-eval-loop.js +0 -241
|
@@ -9,6 +9,25 @@ const { baseDetector, stripAnsi } = require('./base');
|
|
|
9
9
|
|
|
10
10
|
const GEMINI_STATUS_FRAGMENT_RE = /^(?:[\s\d•◦·∙●○✦✧◆◇◐◓◑◒|/\\-]+|Thinking\.{0,3}|Working\.{0,3}|Running\.{0,3}|Responding\.{0,3}|Loading\.{0,3}|esc\s+to\s+(?:cancel|interrupt)|ctrl\+c\s+to\s+(?:quit|cancel)|press\s+enter\s+to\s+send|shift\+enter\s+for\s+newline)$/iu;
|
|
11
11
|
|
|
12
|
+
// The WORKING subset of the status vocabulary. Two precise signals, both shown
|
|
13
|
+
// only mid-generation: the in-flight "esc to cancel/interrupt" hint, and a
|
|
14
|
+
// STANDALONE spinner/status line ("✦ Thinking…"). Anchoring the verb to a whole
|
|
15
|
+
// status line keeps ordinary prose ("I'm working on the fix") from matching, and
|
|
16
|
+
// the idle composer hints ("press enter to send", "ctrl+c to quit") are excluded
|
|
17
|
+
// entirely — so it never mislabels an idle session as generating. server.js's
|
|
18
|
+
// generating-gate uses this to suppress the idle-notify so a long, output-quiet
|
|
19
|
+
// Gemini turn whose composer matches a global prompt pattern is not flagged
|
|
20
|
+
// "Needs You". (Gemini has no detectWaitingInput hook, so this is its only guard.)
|
|
21
|
+
const GEMINI_INTERRUPT_HINT_RE = /\besc\s+to\s+(?:cancel|interrupt)\b/i;
|
|
22
|
+
const GEMINI_WORKING_STATUS_LINE_RE = /^[\s•◦·∙●○✦✧◆◇◐◓◑◒|/\\-]*(?:Thinking|Working|Running|Responding|Loading)\b\.{0,3}\s*$/i;
|
|
23
|
+
function detectActivelyGenerating(text) {
|
|
24
|
+
// Split on newlines FIRST (base.stripAnsi drops them), then strip per line.
|
|
25
|
+
return String(text || '').split(/\r?\n/).slice(-12).some(line => {
|
|
26
|
+
const t = stripAnsi(line).trim();
|
|
27
|
+
return GEMINI_INTERRUPT_HINT_RE.test(t) || GEMINI_WORKING_STATUS_LINE_RE.test(t);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
12
31
|
function isCursorAddressedRedraw(data) {
|
|
13
32
|
const s = String(data || '');
|
|
14
33
|
return (
|
|
@@ -33,4 +52,6 @@ module.exports = {
|
|
|
33
52
|
}
|
|
34
53
|
return true;
|
|
35
54
|
},
|
|
55
|
+
|
|
56
|
+
detectActivelyGenerating,
|
|
36
57
|
};
|
|
@@ -11,6 +11,8 @@ const { baseDetector } = require('./base');
|
|
|
11
11
|
const claudeCode = require('./claude-code');
|
|
12
12
|
const codex = require('./codex');
|
|
13
13
|
const gemini = require('./gemini');
|
|
14
|
+
const opencode = require('./opencode');
|
|
15
|
+
const cursor = require('./cursor');
|
|
14
16
|
|
|
15
17
|
// Provider-id → detector. Adding a new provider is just an import + entry.
|
|
16
18
|
const _detectors = new Map([
|
|
@@ -18,6 +20,8 @@ const _detectors = new Map([
|
|
|
18
20
|
['codex', codex],
|
|
19
21
|
['gemini', gemini],
|
|
20
22
|
['gemini-cli', gemini],
|
|
23
|
+
['opencode', opencode],
|
|
24
|
+
['cursor', cursor],
|
|
21
25
|
]);
|
|
22
26
|
|
|
23
27
|
function getStateDetector(providerId) {
|
|
@@ -25,6 +29,30 @@ function getStateDetector(providerId) {
|
|
|
25
29
|
return baseDetector;
|
|
26
30
|
}
|
|
27
31
|
|
|
32
|
+
// Single authoritative "is this session blocked at a LIVE approval/choice widget
|
|
33
|
+
// right now?" decision, delegated to the provider's own state detector. This is
|
|
34
|
+
// the one place the banner path should ask — replacing global, provider-blind
|
|
35
|
+
// content regexes. Hide-unless-confident: returns live only when the detector
|
|
36
|
+
// positively confirms an approval/choice widget AND no ready/finished composer is
|
|
37
|
+
// on screen (a live widget REPLACES the composer). Unknown providers / detectors
|
|
38
|
+
// without a detectWaitingInput hook → {live:false}.
|
|
39
|
+
function isSessionAtLivePrompt(providerId, text) {
|
|
40
|
+
const detector = getStateDetector(providerId);
|
|
41
|
+
try {
|
|
42
|
+
const wi = typeof detector.detectWaitingInput === 'function' ? detector.detectWaitingInput(text) : null;
|
|
43
|
+
const reason = wi && wi.reason;
|
|
44
|
+
if (reason !== 'approval' && reason !== 'choice') return { live: false, reason: null };
|
|
45
|
+
const readyComposer = typeof detector.detectReadyComposer === 'function' && detector.detectReadyComposer(text);
|
|
46
|
+
const turnFinished = typeof detector.detectTurnFinished === 'function' && detector.detectTurnFinished(text);
|
|
47
|
+
if (readyComposer || turnFinished) return { live: false, reason: null };
|
|
48
|
+
return { live: true, reason };
|
|
49
|
+
} catch {
|
|
50
|
+
// A detector throwing must never break the caller's idle-notify path; default
|
|
51
|
+
// to not-live (hide-unless-confident).
|
|
52
|
+
return { live: false, reason: null };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
28
56
|
function registerStateDetector(providerId, detector) {
|
|
29
57
|
if (!providerId || !detector) return;
|
|
30
58
|
_detectors.set(providerId, detector);
|
|
@@ -40,6 +68,7 @@ function listStateDetectors() {
|
|
|
40
68
|
|
|
41
69
|
module.exports = {
|
|
42
70
|
getStateDetector,
|
|
71
|
+
isSessionAtLivePrompt,
|
|
43
72
|
registerStateDetector,
|
|
44
73
|
listStateDetectors,
|
|
45
74
|
baseDetector,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// OpenCode TUI state detector.
|
|
3
|
+
//
|
|
4
|
+
// OpenCode redraws prompt/footer/status regions and can re-emit startup
|
|
5
|
+
// diagnostics while the agent is actually sitting at its input prompt. Those
|
|
6
|
+
// frames should still paint in the terminal, but they must not be treated as
|
|
7
|
+
// model activity. Approval widgets and real tool output remain active.
|
|
8
|
+
|
|
9
|
+
const { baseDetector } = require('./base');
|
|
10
|
+
|
|
11
|
+
const OPENCODE_FOOTER_LINE_RE = /^(?:gpt|claude|codex|gemini|opencode|deepseek|kimi|moonshot|qwen|llama|mistral)[\w.+-]*(?:\s+[\w.+-]+){0,8}\s+[·-]\s+(?:~|\/|\.\.?\/)/i;
|
|
12
|
+
const OPENCODE_PROMPT_LINE_RE = /^(?:>|›|❯)\s*(?:\S.*)?$/;
|
|
13
|
+
const OPENCODE_BUSY_LINE_RE = /^(?:[•●◦▪·*]\s*)?(?:(?:Waiting\s+for\s+background\s+terminal\b.*)|(?:Working|Thinking|Reading|Writing|Editing|Running|Searching|Planning|Analyzing|Calling|Using|Processing|Crunching)\b.*\b(?:esc|interrupt|cancel)\b)/i;
|
|
14
|
+
const OPENCODE_PASSIVE_STATUS_LINE_RE = /^(?:[•●◦▪·*]\s*)?(?:Ready|Waiting|Idle|Stopped|Done|Complete|Completed)\b/i;
|
|
15
|
+
const OPENCODE_CONTROL_HINT_RE = /^(?:esc|ctrl-c|ctrl\+c|press\s+enter)\b.*(?:interrupt|cancel|confirm|send)/i;
|
|
16
|
+
const OPENCODE_SKILL_WARNING_RE = /^(?:⚠\s*)?Skipped loading\s+\d+\s+skill\(s\)\s+due to invalid SKILL\.md files\./i;
|
|
17
|
+
const OPENCODE_SKILL_DESCRIPTION_RE = /^\/.*\/SKILL\.md:\s+invalid description:\s+exceeds maximum length of\s+\d+\s+characters$/i;
|
|
18
|
+
|
|
19
|
+
function stripAnsiPreserveLines(data) {
|
|
20
|
+
return String(data || '')
|
|
21
|
+
// Cursor-addressed redraws otherwise collapse multiple rows together after
|
|
22
|
+
// stripping CSI. Preserve row boundaries before removing control codes.
|
|
23
|
+
.replace(/\x1b\[[0-9]+;[0-9]+[Hf]/g, '\n')
|
|
24
|
+
.replace(/\x1b\[[0-9]+[ABCD]/g, '\n')
|
|
25
|
+
.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, '')
|
|
26
|
+
.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, '')
|
|
27
|
+
.replace(/\r/g, '\n')
|
|
28
|
+
.replace(/[\x00-\x09\x0b\x0c\x0e-\x1f\x7f]/g, '');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function printableLines(data) {
|
|
32
|
+
return stripAnsiPreserveLines(data)
|
|
33
|
+
.replace(/\u00a0/g, ' ')
|
|
34
|
+
.split(/\n+/)
|
|
35
|
+
.map(line => line.trim())
|
|
36
|
+
.filter(Boolean);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isOpenCodePassiveLine(line) {
|
|
40
|
+
const text = String(line || '').trim();
|
|
41
|
+
if (!text) return true;
|
|
42
|
+
return OPENCODE_FOOTER_LINE_RE.test(text) ||
|
|
43
|
+
OPENCODE_PROMPT_LINE_RE.test(text) ||
|
|
44
|
+
OPENCODE_PASSIVE_STATUS_LINE_RE.test(text) ||
|
|
45
|
+
OPENCODE_CONTROL_HINT_RE.test(text) ||
|
|
46
|
+
OPENCODE_SKILL_WARNING_RE.test(text) ||
|
|
47
|
+
OPENCODE_SKILL_DESCRIPTION_RE.test(text);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isOpenCodeBusyLine(line) {
|
|
51
|
+
return OPENCODE_BUSY_LINE_RE.test(String(line || '').trim());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The agent is mid-turn when its busy/spinner line ("Working… esc to cancel") is on
|
|
55
|
+
// screen. server.js's generating-gate uses this to suppress the idle-notify so a
|
|
56
|
+
// long, output-quiet OpenCode turn whose composer matches a global prompt pattern is
|
|
57
|
+
// not mislabeled "Needs You". Tail-scoped; same busy signal detectWaitingInput gates.
|
|
58
|
+
function detectActivelyGenerating(text) {
|
|
59
|
+
return printableLines(text).slice(-12).some(isOpenCodeBusyLine);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function detectWaitingInput(text) {
|
|
63
|
+
const lines = printableLines(text).slice(-10);
|
|
64
|
+
if (!lines.length) return null;
|
|
65
|
+
if (lines.some(isOpenCodeBusyLine)) return null;
|
|
66
|
+
if (!lines.some(line => OPENCODE_PROMPT_LINE_RE.test(line))) return null;
|
|
67
|
+
return { reason: 'input' };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
...baseDetector,
|
|
72
|
+
id: 'opencode',
|
|
73
|
+
// OpenCode progress can be sparse, but prompt/footer redraws are filtered
|
|
74
|
+
// below. Keep a provider hold only for meaningful activity frames.
|
|
75
|
+
idleDebounceMs: 10000,
|
|
76
|
+
|
|
77
|
+
isActiveChunk(data) {
|
|
78
|
+
if (!baseDetector.isActiveChunk(data)) return false;
|
|
79
|
+
const lines = printableLines(data);
|
|
80
|
+
if (lines.length && lines.every(line => isOpenCodePassiveLine(line) && !isOpenCodeBusyLine(line))) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
isStatusOnlyChunk(data) {
|
|
87
|
+
const lines = printableLines(data);
|
|
88
|
+
return !!(lines.length && lines.every(line => isOpenCodePassiveLine(line) || isOpenCodeBusyLine(line)));
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
isBusyStatusChunk(data) {
|
|
92
|
+
const lines = printableLines(data);
|
|
93
|
+
return lines.some(isOpenCodeBusyLine);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
detectWaitingInput,
|
|
97
|
+
detectActivelyGenerating,
|
|
98
|
+
_test: {
|
|
99
|
+
printableLines,
|
|
100
|
+
isOpenCodePassiveLine,
|
|
101
|
+
isOpenCodeBusyLine,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Markdown Review Pane — Design System
|
|
2
|
+
|
|
3
|
+
**Status:** Implemented · 2026-05-21
|
|
4
|
+
**Scope:** `#review&type=doc` workspace inside the Code Review panel
|
|
5
|
+
**Files:** `claude-task-manager/public/css/reviews.css`, `claude-task-manager/public/js/reviews.js`
|
|
6
|
+
|
|
7
|
+
This doc captures the design rationale behind the May 2026 markdown-review
|
|
8
|
+
redesign so future work doesn't reintroduce the patterns we deliberately
|
|
9
|
+
removed.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Problem we solved
|
|
14
|
+
|
|
15
|
+
The original markdown review pane was a code-editor surface re-skinned for
|
|
16
|
+
prose:
|
|
17
|
+
|
|
18
|
+
- Line-number gutter always visible in the rendered/docs view
|
|
19
|
+
- Single 24/19/16px heading scale, no clear hierarchy between H1 and H4
|
|
20
|
+
- Inline code rendered in **amber** (`#e0af68` Tokyo Night yellow), making
|
|
21
|
+
every identifier read as a warning
|
|
22
|
+
- TOC sidebar prefixed every entry with a literal `#` glyph; hierarchy
|
|
23
|
+
conveyed by glyph repetition (`#`, `##`, `###`) instead of indentation
|
|
24
|
+
- Hardcoded RGBA tints from the dark palette (`rgba(122,162,247,0.06)`)
|
|
25
|
+
showed barely-visible on the light theme bg
|
|
26
|
+
- Workspace bg matched the page bg, so code blocks didn't read as
|
|
27
|
+
contained content
|
|
28
|
+
- Article max-width of 920px exceeded the 80-character readability sweet
|
|
29
|
+
spot
|
|
30
|
+
|
|
31
|
+
The result felt like a `cat foo.md` dump with extra chrome, not a designed
|
|
32
|
+
reading surface.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Design tokens (theme-aware)
|
|
37
|
+
|
|
38
|
+
The whole redesign uses CSS custom properties from the existing CTM
|
|
39
|
+
palette. Both light and dark are defined in `public/index.html`:
|
|
40
|
+
|
|
41
|
+
| Token | Dark | Light | Role in the markdown pane |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| `--bg` | `#1a1b26` | `#f6f7f9` | Workspace surface |
|
|
44
|
+
| `--bg-light` | `#24283b` | `#ffffff` | Code-block & elevated card bg |
|
|
45
|
+
| `--bg-lighter` | `#1f2333` | `#eceef2` | Recessed (gutters, table th) |
|
|
46
|
+
| `--fg` | `#c0caf5` | `#0f172a` | Body text, primary headings |
|
|
47
|
+
| `--fg-dim` | `#a9b1d6` | `#3d4b5e` | H4, secondary metadata |
|
|
48
|
+
| `--fg-muted` | `#7f88a8` | `#52606f` | H5/H6 (kicker), line-gutter |
|
|
49
|
+
| `--accent` | `#7aa2f7` | `#3b66e0` | Links, active TOC rail, focus |
|
|
50
|
+
| `--accent-soft` | `rgba(122,162,247,0.13)` | `rgba(59,102,224,0.10)` | Inline code bg, segmented active fill, hovered block bg |
|
|
51
|
+
| `--border` | `#414868` | `rgba(15,23,42,0.10)` | H2 hairline, hr, card outline |
|
|
52
|
+
|
|
53
|
+
No hardcoded hex in the new CSS. Every color flows from the token system,
|
|
54
|
+
so the next theme palette retune Just Works.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Five-level type scale
|
|
59
|
+
|
|
60
|
+
| Level | Size | Weight | Treatment |
|
|
61
|
+
|---|---|---|---|
|
|
62
|
+
| H1 | 28px | 700 | `letter-spacing: -0.01em`, 16px bottom margin |
|
|
63
|
+
| H2 | 22px | 650 | 28px top margin, 1px bottom hairline (`--border`) |
|
|
64
|
+
| H3 | 17px | 600 | 22px top margin |
|
|
65
|
+
| H4 | 15px | 600 | Muted color (`--fg-dim`) — sub-section label |
|
|
66
|
+
| H5/H6 | 12px | 700 | Uppercase, 0.08em tracking — used as "eyebrow" |
|
|
67
|
+
|
|
68
|
+
Body text: **15px / line-height 1.7 / `--fg`**. The 1.7 line-height puts
|
|
69
|
+
prose squarely in the GitHub-docs / Stripe-docs comfort band; the dense
|
|
70
|
+
1.62 we had before read as compressed.
|
|
71
|
+
|
|
72
|
+
`scroll-margin-top: 16px` on every heading so deep-link anchors don't
|
|
73
|
+
collide with sticky chrome.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Layout
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
┌───────────────────────────────────────────────────────────────┐
|
|
81
|
+
│ CTM topbar │
|
|
82
|
+
├─────────────┬─────────────────────────────────────────────────┤
|
|
83
|
+
│ TOC rail │ .cr-doc-article (max-width 800px) │
|
|
84
|
+
│ │ ┌─────────────────────────────────────────┐ │
|
|
85
|
+
│ • Heading │ │ # Document Title │ │
|
|
86
|
+
│ Heading │ │ ───────── │ │
|
|
87
|
+
│ Heading │ │ ## Section H2 ─────────────────────────│ │
|
|
88
|
+
│ │ │ │ │
|
|
89
|
+
│ ─ active │ │ Body paragraph rendered at 15/1.7… │ │
|
|
90
|
+
│ │ │ │ │
|
|
91
|
+
│ │ │ `inline code` reads as body, faintly │ │
|
|
92
|
+
│ │ │ tinted accent-soft. │ │
|
|
93
|
+
│ │ │ │ │
|
|
94
|
+
│ │ │ ``` │ │
|
|
95
|
+
│ │ │ block code on --bg-light w/ border │ │
|
|
96
|
+
│ │ │ ``` │ │
|
|
97
|
+
│ │ └─────────────────────────────────────────┘ │
|
|
98
|
+
└─────────────┴─────────────────────────────────────────────────┘
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- **Article width capped at 800px.** Past ~75 characters per line,
|
|
102
|
+
readability drops sharply (Bringhurst, *The Elements of Typographic
|
|
103
|
+
Style*). 800px at 15px font sits at ~75ch.
|
|
104
|
+
- **Top padding 24px, side padding 32px, bottom padding 96px.** Bottom
|
|
105
|
+
pad lets the user scroll the last section into a comfortable reading
|
|
106
|
+
position rather than glued to the viewport bottom.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## What we hide vs reveal
|
|
111
|
+
|
|
112
|
+
| Element | Default state | Hover/active state |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `.cr-doc-block-lines` (line-range gutter) | Opacity 0, positioned `left: -44px` | Opacity 0.55 on block hover; full opacity in source/split pane |
|
|
115
|
+
| `.cr-doc-comment-btn` (the `+` button) | Opacity 0 | Opacity 1 on block hover, active, or focus-visible |
|
|
116
|
+
| Source-pane line numbers | Visible by default | Same |
|
|
117
|
+
|
|
118
|
+
Rationale: line numbers and the `+` glyph belong with **source-code
|
|
119
|
+
review**. In **rendered mode** they're affordances you reach for, not
|
|
120
|
+
content. Hiding them by default keeps the surface looking like a doc;
|
|
121
|
+
hover/focus brings them back when you need to anchor a review comment.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## TOC sidebar
|
|
126
|
+
|
|
127
|
+
- **No `#` glyph.** Markdown syntax in a parsed UI looked like a bug.
|
|
128
|
+
- **Depth via padding-left.** H1 = 8px, H2 = 14px, H3 = 28px, H4 = 42px,
|
|
129
|
+
H5/H6 = 56px. Combined with shrinking font size (12 → 11.5 → 11) and
|
|
130
|
+
color stepping (`--fg` → `--fg-dim` → `--fg-muted`) the hierarchy
|
|
131
|
+
reads at a glance.
|
|
132
|
+
- **Active state.** Subtle `--accent-soft` fill + `box-shadow: inset 2px
|
|
133
|
+
0 0 var(--accent)` rail on the left edge. Reads as "you are here"
|
|
134
|
+
without dominating.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Scroll-spy
|
|
139
|
+
|
|
140
|
+
`setupDocScrollSpy()` in `reviews.js` uses an `IntersectionObserver`
|
|
141
|
+
scoped to `.cr-diff-area`. Each `.cr-doc-block` is observed; the topmost
|
|
142
|
+
intersecting block (by `boundingClientRect.top`, smallest = closest to
|
|
143
|
+
top of viewport) becomes the "active" reader position. Its nearest
|
|
144
|
+
preceding heading block is then resolved (`headingFor` map) and that
|
|
145
|
+
heading's TOC entry gets the `.active` class.
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
rootMargin: '-12px 0px -70% 0px'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
That means a heading is "active" only while it's in the top **30%** of
|
|
152
|
+
the visible pane — same band Stripe Docs and Notion use. Anything below
|
|
153
|
+
that doesn't fight for the active marker.
|
|
154
|
+
|
|
155
|
+
The observer is rebuilt every render (the DOM is reset). Old observer
|
|
156
|
+
is `disconnect()`-ed first so we don't leak listeners.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Non-goals
|
|
161
|
+
|
|
162
|
+
- **No syntax highlighting on `<pre><code>` blocks.** The existing
|
|
163
|
+
markdown renderer doesn't ship highlight.js; adding it is a larger
|
|
164
|
+
scope. Block code is monospaced on `--bg-light` with a border and the
|
|
165
|
+
user reads it as code through layout cues, not color.
|
|
166
|
+
- **No print stylesheet.** Out of scope.
|
|
167
|
+
- **No front-matter parsing.** YAML-style front matter (if any) renders
|
|
168
|
+
as ordinary markdown. Adding a `<div class="front-matter">` wrapper
|
|
169
|
+
needs a renderer change; deferred.
|
|
170
|
+
- **No collapsible H2 sections.** Considered, rejected — collapsing
|
|
171
|
+
hides content the reader explicitly opened a doc to see.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Verification
|
|
176
|
+
|
|
177
|
+
Validated on an isolated dev instance (`/ctm-dev`, random port 4464),
|
|
178
|
+
loading a real markdown spec
|
|
179
|
+
(`wall-e/docs/superpowers/specs/2026-04-15-mempalace-gap-analysis-v2.md`,
|
|
180
|
+
22 headings, 64 blocks):
|
|
181
|
+
|
|
182
|
+
**Dark mode, light mode**, both verified via `getComputedStyle`:
|
|
183
|
+
|
|
184
|
+
| Check | Result |
|
|
185
|
+
|---|---|
|
|
186
|
+
| TOC `#` glyph removed | `iconText: ""`, `display: none` |
|
|
187
|
+
| TOC indentation by level | 8px → 14px → 28px |
|
|
188
|
+
| Article width | 800px |
|
|
189
|
+
| Workspace bg | `--bg` resolves correctly per theme |
|
|
190
|
+
| H1 | 28px / 700 |
|
|
191
|
+
| H2 | 22px + 1px `--border` bottom |
|
|
192
|
+
| Line-gutter (rendered) | opacity 0, off-screen |
|
|
193
|
+
| Comment `+` (default) | opacity 0 (revealed on hover/active/focus) |
|
|
194
|
+
| Inline code | accent-soft bg + `--fg` text (no amber) |
|
|
195
|
+
| Segmented "active" | accent-soft fill (not solid accent) |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Related
|
|
200
|
+
|
|
201
|
+
- [CTM light-mode contrast redesign](https://github.com/Student ExampleLi/tools/commit/0ce352b)
|
|
202
|
+
— established the `--fg-dim` / `--fg-muted` / `--accent-soft` tokens
|
|
203
|
+
this work depends on.
|
|
204
|
+
- [xterm.js minimumContrastRatio](https://github.com/Student ExampleLi/tools/commit/28576de)
|
|
205
|
+
— same "don't fight the theme palette, fix the contrast at the edge"
|
|
206
|
+
principle applied to terminals.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Portkey Gateway Provider UX
|
|
2
2
|
|
|
3
3
|
Date: 2026-05-17
|
|
4
|
-
|
|
4
|
+
Updated: 2026-05-20
|
|
5
|
+
Status: revised and implemented
|
|
5
6
|
|
|
6
7
|
## Context
|
|
7
8
|
|
|
@@ -14,16 +15,49 @@ Wall-E already has two separate ideas that should not be collapsed:
|
|
|
14
15
|
|
|
15
16
|
Portkey belongs on a third axis: **connection / transport**. A provider instance can be "OpenAI via Portkey" or "Anthropic via Portkey" while still using the OpenAI or Anthropic runtime adapter.
|
|
16
17
|
|
|
17
|
-
##
|
|
18
|
+
## Research Notes
|
|
19
|
+
|
|
20
|
+
Portkey's current public docs support the implementation shape:
|
|
21
|
+
|
|
22
|
+
- The OpenAI-compatible setup is still "change base URL to `https://api.portkey.ai/v1` and use a Portkey API key".
|
|
23
|
+
- The universal API supports OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages against the gateway, so Portkey should be modeled as transport rather than as a standalone upstream provider.
|
|
24
|
+
- The model listing endpoint is `GET /v1/models`, requires `x-portkey-api-key`, and can filter by `provider`/`ai_service`. Its response includes provider-qualified ids such as `@ai-provider-slug/gpt-5`, which CTM must preserve instead of filtering through the built-in catalog.
|
|
25
|
+
- Portkey Models is also a public model/pricing catalog. Provider pricing JSON is available at `https://configs.portkey.ai/pricing/{provider}.json`, individual model pricing is available at `https://api.portkey.ai/model-configs/pricing/{provider}/{model}`, and the open catalog repository publishes the current provider list. This is provider-agnostic and must not be limited to provider families CTM already has direct keys for.
|
|
26
|
+
|
|
27
|
+
## Revised UX Model
|
|
18
28
|
|
|
19
29
|
The `#models` page should use this vocabulary:
|
|
20
30
|
|
|
21
|
-
- **Provider**: upstream API/runtime family. Examples: OpenAI, Anthropic, Google Gemini.
|
|
31
|
+
- **Provider**: upstream API/runtime family. Examples: OpenAI, Anthropic, Google Gemini. Provider cards are the primary overview because CTM has few provider families.
|
|
22
32
|
- **Connection**: how requests reach the provider. Examples: Direct API key, Portkey gateway, Claude CLI subscription, Codex CLI subscription, OAuth proxy.
|
|
23
33
|
- **Route**: a concrete model plus provider instance. Examples: `gpt-5.5 · OpenAI · Direct`, `gpt-5.5 · OpenAI · Portkey prod`.
|
|
34
|
+
- **Gateway**: shared transport/account configuration that can be enabled per provider family. Portkey is the first gateway.
|
|
35
|
+
- **Portkey Catalog Provider**: a provider family from Portkey's public model catalog, even when CTM has no direct adapter/key for that provider.
|
|
36
|
+
- **Model Catalog**: the long model inventory underneath provider cards. It is collapsed by default because the provider view is the decision surface.
|
|
24
37
|
|
|
25
38
|
This keeps the user from seeing Portkey as a competing "model provider" next to OpenAI and Anthropic. It also explains why a Claude model can be reachable through Portkey while Claude CLI remains a separate subscription-backed route.
|
|
26
39
|
|
|
40
|
+
## 2026-05-20 Product Decision
|
|
41
|
+
|
|
42
|
+
Portkey is enabled and disabled at the **provider** level, not the individual model level.
|
|
43
|
+
|
|
44
|
+
The provider card owns the access policy:
|
|
45
|
+
|
|
46
|
+
- `Auto`: prefer direct provider API when configured, otherwise use Portkey if the provider is gateway-only.
|
|
47
|
+
- `Prefer Direct`: use direct provider API when available; fall back to Portkey only when direct access is absent.
|
|
48
|
+
- `Prefer Portkey`: use the Portkey connection for that provider when available; fall back to direct only when no Portkey route exists.
|
|
49
|
+
|
|
50
|
+
The Gateway section owns account-level operations:
|
|
51
|
+
|
|
52
|
+
- connect/edit the Portkey gateway credential
|
|
53
|
+
- sync the Portkey model catalog
|
|
54
|
+
- apply Portkey to all providers verified by model sync
|
|
55
|
+
- apply Portkey to all providers imported from Portkey's catalog
|
|
56
|
+
- disable Portkey as the default by returning provider policies to `Auto`
|
|
57
|
+
- remove all Portkey gateway connections
|
|
58
|
+
|
|
59
|
+
The Model Catalog remains an inspection surface. It shows imported/discovered models, capabilities, pricing, source, and verification status, but the default access decision belongs on provider cards.
|
|
60
|
+
|
|
27
61
|
## `#models` Page Behavior
|
|
28
62
|
|
|
29
63
|
### Provider Cards
|
|
@@ -42,6 +76,8 @@ Provider cards remain grouped by upstream provider:
|
|
|
42
76
|
- Google Gemini
|
|
43
77
|
- Direct API key
|
|
44
78
|
- Portkey gateway when supported by the configured route
|
|
79
|
+
- Fireworks AI, Together AI, Mistral AI, and other Portkey-only providers
|
|
80
|
+
- Portkey gateway only unless CTM later adds a native direct adapter
|
|
45
81
|
|
|
46
82
|
Each saved provider instance should display a compact connection chip:
|
|
47
83
|
|
|
@@ -53,14 +89,60 @@ Each saved provider instance should display a compact connection chip:
|
|
|
53
89
|
|
|
54
90
|
The chip is metadata, not the provider type.
|
|
55
91
|
|
|
56
|
-
|
|
92
|
+
Each cloud provider card also exposes an **Access Route** control:
|
|
93
|
+
|
|
94
|
+
- `Use Portkey` when a Portkey route exists for that provider.
|
|
95
|
+
- `Prefer Direct` for direct-first routing.
|
|
96
|
+
- `Auto` for direct-first with gateway fallback.
|
|
97
|
+
- `Enable Portkey` when the provider has no Portkey route yet.
|
|
98
|
+
|
|
99
|
+
For a provider that exists only through Portkey's catalog, the card must not show a direct route control. It should render as Portkey-only. Unknown Portkey catalog provider families use the OpenAI-compatible runtime against the Portkey gateway and provider-qualified model ids such as `@fireworks-ai/mixtral-8x7b`.
|
|
100
|
+
|
|
101
|
+
This gives users a discoverable per-provider control without forcing route choices across hundreds of model rows.
|
|
102
|
+
|
|
103
|
+
### Gateway Section
|
|
104
|
+
|
|
105
|
+
The Models page includes a first-class **Gateways** section above provider cards.
|
|
106
|
+
|
|
107
|
+
The Portkey gateway card displays:
|
|
108
|
+
|
|
109
|
+
- imported Portkey provider count
|
|
110
|
+
- imported model count
|
|
111
|
+
- last successful sync or last sync error
|
|
112
|
+
- `Connect Portkey` / `Edit Gateway`
|
|
113
|
+
- `Sync now`
|
|
114
|
+
- `Apply to Portkey providers`
|
|
115
|
+
- `Disable as default`
|
|
116
|
+
- `Remove`
|
|
117
|
+
|
|
118
|
+
Portkey model discovery runs hourly in the Wall-E daemon, runs on startup after the daemon is listening, and can be triggered manually from `Sync now`. Sync has two data sources:
|
|
119
|
+
|
|
120
|
+
- The connected gateway `/models` response. This proves what the configured gateway route returns for the user's credential/header set.
|
|
121
|
+
- The public Portkey Models catalog. This is used to import provider families and model/pricing rows that CTM does not know directly, such as Fireworks AI.
|
|
122
|
+
|
|
123
|
+
Sync must not restrict Portkey provider imports to CTM's built-in provider list. It should fetch Portkey's current public catalog provider list, fall back to the documented provider list when the catalog index is unavailable, and import raw/provider-qualified Portkey model ids, including providers and model ids not present in CTM's built-in supported-model catalog.
|
|
124
|
+
|
|
125
|
+
Corporate/devbox Portkey configurations can point at a company gateway host instead of public `api.portkey.ai`. CTM should preserve the gateway URL from local configuration/logs and should not assume that a valid Portkey header set works against the public Portkey host. CTM must not hardcode any company's gateway URL as a fallback.
|
|
57
126
|
|
|
58
|
-
|
|
127
|
+
### Add Provider And Gateway Dialogs
|
|
128
|
+
|
|
129
|
+
The normal Add Provider dialog asks for upstream first, then connection:
|
|
59
130
|
|
|
60
131
|
1. Provider: OpenAI, Anthropic, Google, DeepSeek, Ollama.
|
|
61
132
|
2. Connection: Direct API key or Portkey gateway.
|
|
62
133
|
3. For Direct: show the provider API key and optional base URL.
|
|
63
|
-
|
|
134
|
+
|
|
135
|
+
The Gateway section uses a different Portkey-specific dialog. It must not ask users to choose an upstream provider or provider slug. Portkey is connected once with:
|
|
136
|
+
|
|
137
|
+
- Portkey API key
|
|
138
|
+
- Gateway URL, defaulting to `https://api.portkey.ai/v1` for manual Portkey accounts, or the detected devbox/corporate gateway URL when CTM can read a local devbox Claude configuration
|
|
139
|
+
- optional config id
|
|
140
|
+
- optional virtual key
|
|
141
|
+
- optional local label for the Portkey account/config
|
|
142
|
+
|
|
143
|
+
After saving this single gateway config, CTM stores one gateway credential row. The next Portkey sync creates internal runtime routes for providers discovered from the configured gateway and from Portkey's public model catalog. Provider cards then control whether each discovered provider uses direct API access, Portkey, or automatic fallback. Providers with no direct CTM connection render as Portkey-only.
|
|
144
|
+
|
|
145
|
+
If CTM detects a devbox Claude Portkey header file, the UI may offer a one-click "Use" action. That action stays server-side: the browser receives only masked metadata and booleans such as whether a virtual key exists; raw custom headers and API keys must never be returned by `/api/models/providers` or `/api/models/detect-keys`.
|
|
64
146
|
|
|
65
147
|
Default labels should make the route obvious:
|
|
66
148
|
|
|
@@ -70,8 +152,14 @@ Default labels should make the route obvious:
|
|
|
70
152
|
|
|
71
153
|
Advanced custom headers can still exist, but common Portkey fields should not require users to write JSON.
|
|
72
154
|
|
|
155
|
+
### Model Provider Section
|
|
156
|
+
|
|
157
|
+
The Model Providers section is collapsed by default. The page still shows the Gateways section first because gateway setup is the shared routing control. Searching provider cards expands the Model Providers section so matches are visible.
|
|
158
|
+
|
|
73
159
|
### Model List
|
|
74
160
|
|
|
161
|
+
The Model Catalog section is collapsed by default. Searching models expands the catalog so search results remain visible.
|
|
162
|
+
|
|
75
163
|
The model list should show duplicate model ids as separate routes only when necessary:
|
|
76
164
|
|
|
77
165
|
- If a model exists once, show `GPT-5.5` with a subtle `OpenAI · Direct` chip.
|
|
@@ -81,13 +169,31 @@ The model list should show duplicate model ids as separate routes only when nece
|
|
|
81
169
|
|
|
82
170
|
The saved value should prefer `model_registry.id`, not only the bare model id.
|
|
83
171
|
|
|
172
|
+
Gateway-discovered model rows use:
|
|
173
|
+
|
|
174
|
+
- `source = portkey`
|
|
175
|
+
- `gateway_type = portkey`
|
|
176
|
+
- `verification_status = verified` only when CTM's built-in catalog recognizes the model id; otherwise `unverified`
|
|
177
|
+
- `last_seen_at` from the latest Portkey sync
|
|
178
|
+
|
|
179
|
+
Public Portkey catalog model rows use:
|
|
180
|
+
|
|
181
|
+
- `source = portkey_catalog`
|
|
182
|
+
- `gateway_type = portkey`
|
|
183
|
+
- `verification_status = catalog`
|
|
184
|
+
- provider-qualified model ids such as `@fireworks-ai/mixtral-8x7b`
|
|
185
|
+
- pricing converted from Portkey's cents-per-token values into CTM's dollars-per-1M-token fields
|
|
186
|
+
|
|
187
|
+
Catalog pruning must not delete gateway-discovered or Portkey-catalog rows just because CTM's built-in catalog does not know the id yet.
|
|
188
|
+
|
|
84
189
|
## Conflict Rules
|
|
85
190
|
|
|
86
191
|
1. Exact `model_registry.id` wins.
|
|
87
|
-
2.
|
|
88
|
-
3.
|
|
89
|
-
4. If a bare model id maps to
|
|
90
|
-
5.
|
|
192
|
+
2. Explicit task/model defaults win over provider route policy.
|
|
193
|
+
3. Provider route policy resolves duplicate direct and Portkey rows for the same provider family.
|
|
194
|
+
4. If a bare model id maps to exactly one enabled route, it is safe to resolve.
|
|
195
|
+
5. If a bare model id maps to multiple enabled routes and provider route policy cannot disambiguate, return an ambiguity error that names the available routes.
|
|
196
|
+
6. Never select the newest provider row as a silent tie-breaker when direct and Portkey routes share the same model id.
|
|
91
197
|
|
|
92
198
|
## Implementation Phases
|
|
93
199
|
|
|
@@ -99,6 +205,8 @@ Document the UX and routing model, including the `#models` page behavior and dup
|
|
|
99
205
|
|
|
100
206
|
- Add OpenAI custom-header support so OpenAI-through-Portkey can send Portkey headers.
|
|
101
207
|
- Add shared Portkey metadata helpers for naming, default base URLs, and route labels.
|
|
208
|
+
- Add public Portkey Models catalog sync independent of CTM's existing provider list.
|
|
209
|
+
- Allow unknown Portkey-only provider families to use the OpenAI-compatible runtime against the Portkey gateway.
|
|
102
210
|
- Extend provider detection so `PORTKEY_API_KEY` is treated as a gateway credential, not as Anthropic-only auto-detection.
|
|
103
211
|
- Add tests for OpenAI Portkey headers and duplicate route resolution.
|
|
104
212
|
|
|
@@ -117,38 +225,21 @@ Document the UX and routing model, including the `#models` page behavior and dup
|
|
|
117
225
|
|
|
118
226
|
## Verification Results
|
|
119
227
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
- CTM: `https://localhost:3466/?token=...#models`
|
|
123
|
-
- Wall-E: `127.0.0.1:3467`
|
|
124
|
-
- Data dir: `/tmp/ctm-portkey-test`
|
|
125
|
-
- Mock Portkey gateway: `http://127.0.0.1:4577/v1`
|
|
126
|
-
|
|
127
|
-
The seeded real-life scenario used two OpenAI connections with the same model id:
|
|
128
|
-
|
|
129
|
-
- `openai-default:gpt-4o-mini` as direct OpenAI.
|
|
130
|
-
- `openai-portkey-prod:gpt-4o-mini` as OpenAI via Portkey.
|
|
131
|
-
|
|
132
|
-
The CTM `test-connection` route sent a live `GET /v1/models` request through Wall-E's OpenAI adapter to the mock gateway. The mock observed:
|
|
133
|
-
|
|
134
|
-
- `Authorization: Bearer unit-portkey-key`
|
|
135
|
-
- `x-portkey-config: cfg-prod`
|
|
136
|
-
- `x-portkey-provider: openai`
|
|
137
|
-
|
|
138
|
-
The browser verification captured desktop and mobile screenshots in `/tmp/portkey-models-desktop.png` and `/tmp/portkey-models-mobile.png`. It checked:
|
|
139
|
-
|
|
140
|
-
- Duplicate direct and Portkey OpenAI routes render as separate connections.
|
|
141
|
-
- Portkey route details show `config cfg-prod`.
|
|
142
|
-
- Header `+ Add Provider` keeps the Provider selector visible.
|
|
143
|
-
- Portkey mode exposes gateway fields and labels the key as `Portkey API Key`.
|
|
144
|
-
- Anthropic defaults to `https://api.portkey.ai`; OpenAI defaults to `https://api.portkey.ai/v1`.
|
|
145
|
-
- The Portkey provider-slug placeholder follows the selected provider.
|
|
146
|
-
- The Portkey dialog itself fits a 390px mobile viewport.
|
|
228
|
+
The implemented provider-level gateway path is covered by:
|
|
147
229
|
|
|
148
|
-
|
|
230
|
+
- Portkey sync tests that import unknown gateway model ids, import Portkey-only catalog provider families such as Fireworks AI, mark CTM-known ids as `verified`, mark unknown gateway ids as `unverified`, and prove catalog pruning preserves gateway/catalog rows.
|
|
231
|
+
- Provider route-policy tests that prefer Portkey or direct connections per provider and fall back when the requested route is unavailable.
|
|
232
|
+
- Chat routing tests that resolve duplicate direct/Portkey bare model ids using the provider policy instead of raising avoidable ambiguity.
|
|
233
|
+
- Model admin HTTP tests for gateway summaries and provider route policy updates.
|
|
234
|
+
- Static UI tests for the providerless Portkey Gateway dialog, provider Access Route controls, collapsed-by-default Model Providers, and collapsed-by-default Model Catalog.
|
|
235
|
+
- Playwright render tests for the Models page gateway card, provider route buttons, Portkey-only provider cards, collapsed provider/catalog expansion, and provider policy POST behavior.
|
|
236
|
+
- Full CTM regression tests.
|
|
149
237
|
|
|
150
238
|
## References
|
|
151
239
|
|
|
152
240
|
- https://portkey.ai/docs/integrations/libraries/openai-compatible
|
|
241
|
+
- https://portkey.ai/docs/api-reference/inference-api/models/models
|
|
242
|
+
- https://portkey.ai/docs/product/ai-gateway/universal-api
|
|
243
|
+
- https://portkey.ai/docs/product/model-catalog/portkey-models
|
|
153
244
|
- https://portkey.ai/docs/integrations/libraries/claude-code
|
|
154
245
|
- https://portkey.ai/docs/integrations/libraries/codex
|