@inneranimalmedia/agentsam-sdk 2.6.5 → 2.6.8
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/AGENTSAM.md +29 -0
- package/README.md +37 -0
- package/apps/README.md +5 -0
- package/apps/cad-creator/README.md +4 -4
- package/apps/cad-creator/shared/cad/package.json +1 -1
- package/apps/client-cms-editor/AGENTS.md +12 -7
- package/apps/client-cms-editor/README.md +76 -48
- package/apps/client-cms-editor/agentsam.app.json +26 -9
- package/apps/client-cms-editor/backend/package.json +20 -3
- package/apps/client-cms-editor/backend/src/api/client.ts +134 -101
- package/apps/client-cms-editor/backend/src/index.ts +1 -1
- package/apps/client-cms-editor/backend/src/model.ts +11 -115
- package/apps/client-cms-editor/backend/src/preview/bridge.ts +1 -1
- package/apps/client-cms-editor/backend/tsconfig.json +6 -1
- package/apps/client-cms-editor/bin/agentsam-cms.js +262 -0
- package/apps/client-cms-editor/bin/agentsam-cms.mjs +2 -228
- package/apps/client-cms-editor/frontend/package.json +16 -7
- package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +9 -41
- package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +19 -174
- package/apps/client-cms-editor/frontend/src/adapters/heuristic.ts +29 -0
- package/apps/client-cms-editor/frontend/src/adapters/http.ts +628 -0
- package/apps/client-cms-editor/frontend/src/adapters/memory.ts +510 -0
- package/apps/client-cms-editor/frontend/src/editor/CmsEditor.tsx +213 -0
- package/apps/client-cms-editor/frontend/src/editor/CmsEditorProvider.tsx +20 -0
- package/apps/client-cms-editor/frontend/src/editor/canvas/PreviewCanvas.tsx +53 -0
- package/apps/client-cms-editor/frontend/src/{CmsEditor.tsx → editor/legacy/CmsEditorPrototype.tsx} +52 -23
- package/apps/client-cms-editor/frontend/src/editor/useCmsEditorController.ts +218 -0
- package/apps/client-cms-editor/frontend/src/index.ts +19 -5
- package/apps/client-cms-editor/frontend/src/lib/agent-host.ts +24 -0
- package/apps/client-cms-editor/frontend/src/main.tsx +82 -8
- package/apps/client-cms-editor/frontend/src/mount.tsx +92 -30
- package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +1 -1
- package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +8 -8
- package/apps/client-cms-editor/frontend/src/styles/studio.css +55 -3
- package/apps/client-cms-editor/frontend/tsconfig.json +12 -1
- package/apps/client-cms-editor/frontend/vite.config.ts +12 -0
- package/apps/client-cms-editor/package-lock.json +973 -134
- package/apps/client-cms-editor/package.json +118 -6
- package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +201 -0
- package/apps/client-cms-editor/reference/harvest/PROVENANCE_HISTORY.txt +10 -0
- package/apps/client-cms-editor/reference/harvest/README.md +8 -0
- package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +135 -0
- package/apps/client-cms-editor/reference/harvest/plans/CHATGPT-IDENTITY-HARVEST.md +83 -0
- package/apps/client-cms-editor/reference/harvest/plans/CMS-EDITOR-HARVEST.md +166 -0
- package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +196 -0
- package/apps/client-cms-editor/reference/harvest/plans/INNERANIMALS-CONTENT-001.md +137 -0
- package/apps/client-cms-editor/reference/harvest/plans/NO-IMPLICIT-SIDE-EFFECTS.md +87 -0
- package/apps/client-cms-editor/reference/harvest/plans/STOREFRONT-SURFACE-MAP.md +140 -0
- package/apps/client-cms-editor/reference/harvest/plans/THEME-INNERANIMALS-HARVEST.md +137 -0
- package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +63 -0
- package/apps/client-cms-editor/reference/harvest/plans/harvest-manifest.json +97 -0
- package/apps/client-cms-editor/reference/harvest/plans/local-cms-harvest-schema.sql +328 -0
- package/apps/client-cms-editor/shared/cms/package.json +17 -7
- package/apps/client-cms-editor/shared/cms/src/adapter.ts +204 -0
- package/apps/client-cms-editor/shared/cms/src/agent-context.ts +7 -5
- package/apps/client-cms-editor/shared/cms/src/editor-types.ts +32 -0
- package/apps/client-cms-editor/shared/cms/src/host.ts +82 -0
- package/apps/client-cms-editor/shared/cms/src/index.ts +4 -0
- package/apps/client-cms-editor/shared/cms/src/map.ts +115 -0
- package/apps/client-cms-editor/shared/cms/src/starter-pack.ts +158 -0
- package/contracts/source-types.v1.json +353 -0
- package/docs/CMS_CONTEXTUAL_COMPOSER.md +1 -1
- package/docs/PRODUCT_LIFECYCLE.md +566 -0
- package/docs/REPO_FILE_MAP.txt +132 -0
- package/docs/THEME_REFINERY.md +2 -2
- package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +40 -20
- package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
- package/docs/plans/LOCAL_STUDIO_DESKTOP_RELEASE_2026-09-29.md +150 -0
- package/migrations/d1/0017_identity_native_oauth.sql +21 -0
- package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
- package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
- package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
- package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
- package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
- package/native/agentsam-machine/Cargo.lock +426 -0
- package/native/agentsam-machine/Cargo.toml +9 -0
- package/native/agentsam-machine/cli/Cargo.toml +21 -0
- package/native/agentsam-machine/cli/README.md +21 -0
- package/native/agentsam-machine/cli/src/main.rs +77 -0
- package/native/agentsam-machine/core/Cargo.toml +22 -0
- package/native/agentsam-machine/core/README.md +14 -0
- package/native/agentsam-machine/core/build.rs +33 -0
- package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
- package/native/agentsam-machine/core/src/assets.rs +790 -0
- package/native/agentsam-machine/core/src/bound.rs +298 -0
- package/native/agentsam-machine/core/src/enrich.rs +706 -0
- package/native/agentsam-machine/core/src/frontend.rs +442 -0
- package/native/agentsam-machine/core/src/lib.rs +1092 -0
- package/native/agentsam-machine/core/src/liquid.rs +528 -0
- package/native/agentsam-machine/core/src/source_types.rs +78 -0
- package/package.json +64 -24
- package/packages/agentsam-brand/README.md +1 -1
- package/packages/agentsam-brand/package.json +4 -4
- package/packages/agentsam-brand/src/index.js +1 -1
- package/packages/agentsam-contracts/package.json +13 -3
- package/packages/agentsam-contracts/src/tools.ts +22 -0
- package/packages/agentsam-errors/package.json +13 -3
- package/packages/agentsam-errors/src/index.js +1 -0
- package/packages/agentsam-errors/src/tool.js +56 -0
- package/packages/agentsam-errors/test/tool.test.mjs +58 -0
- package/packages/agentsam-goap/README.md +52 -0
- package/packages/agentsam-goap/package.json +37 -0
- package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
- package/packages/agentsam-goap/src/adapters/memory.js +199 -0
- package/packages/agentsam-goap/src/contracts.js +226 -0
- package/packages/agentsam-goap/src/control-plane.js +112 -0
- package/packages/agentsam-goap/src/errors.js +157 -0
- package/packages/agentsam-goap/src/index.js +5 -0
- package/packages/agentsam-goap/src/world.js +202 -0
- package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
- package/packages/agentsam-goap/test/world.test.mjs +79 -0
- package/packages/agentsam-knowledge/package.json +18 -4
- package/packages/agentsam-knowledge/src/autorag/index.js +10 -3
- package/packages/agentsam-knowledge/src/backends/index.js +33 -1
- package/packages/agentsam-knowledge/test/autorag.test.mjs +60 -1
- package/packages/agentsam-nav/dist/browser.global.js +21 -18
- package/packages/agentsam-nav/dist/browser.js +6807 -130
- package/packages/agentsam-nav/dist/index.js +6799 -122
- package/packages/agentsam-nav/package.json +24 -6
- package/packages/agentsam-queue-control/README.md +1 -1
- package/packages/agentsam-queue-control/package.json +7 -2
- package/packages/agentsam-rapid-rust/src/main.rs +1 -1
- package/packages/agentsam-repository/package.json +13 -3
- package/packages/agentsam-repository/src/goap.js +13 -14
- package/packages/agentsam-repository/src/source-types.js +8 -0
- package/packages/agentsam-repository/src/tickets.js +15 -22
- package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
- package/packages/agentsam-vault/package.json +14 -4
- package/packages/agentsam-workbench/package.json +15 -4
- package/packages/agentsam-workbench/src/agent/ToolPermissionRequest.tsx +94 -0
- package/packages/agentsam-workbench/src/agent/index.ts +2 -0
- package/packages/agentsam-workbench/src/agent/tool-permission.css +134 -0
- package/packages/connectors/cloudflare/package.json +15 -3
- package/packages/connectors/cloudflare/src/api-client.js +3 -2
- package/packages/connectors/cloudflare/src/families/vectorize.js +127 -0
- package/packages/connectors/cloudflare/src/index.js +1 -0
- package/packages/heuristic-theme/README.md +2 -2
- package/packages/heuristic-theme/package.json +8 -3
- package/packages/heuristic-theme/src/registry.js +2 -2
- package/packages/heuristic-theme/src/theme.js +1 -1
- package/packages/heuristic-theme/test/theme.test.mjs +1 -1
- package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
- package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +27 -7
- package/packages/identity/README.md +2 -2
- package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +18 -15
- package/packages/identity/migrations/apply-portable.js +109 -0
- package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +1 -1
- package/packages/identity/migrations/sqlite/005_identity_company_native.sql +52 -0
- package/packages/identity/package.json +27 -6
- package/packages/identity/schema/agentsam.identity/manifest.json +101 -0
- package/packages/identity/scripts/local-identity-bridge.mjs +13 -7
- package/packages/identity/scripts/preview-auth-portal.mjs +6 -6
- package/packages/identity/src/adapters/cloudflare-d1/index.js +8 -401
- package/packages/identity/src/adapters/iam-compat/index.js +540 -0
- package/packages/identity/src/adapters/portable-d1/index.js +18 -0
- package/packages/identity/src/adapters/portable-store.js +479 -0
- package/packages/identity/src/adapters/sqlite/index.js +13 -312
- package/packages/identity/src/contracts/auth-config.js +0 -1
- package/packages/identity/src/contracts/identity-store.js +56 -5
- package/packages/identity/src/contracts/provider.js +1 -0
- package/packages/identity/src/contracts/sign-in-options.js +104 -0
- package/packages/identity/src/core/constants.js +1 -1
- package/packages/identity/src/core/session-policy.js +31 -0
- package/packages/identity/src/frontend/auth-portal/pages/login.html +6 -6
- package/packages/identity/src/frontend/auth-portal/pages/reset.html +5 -5
- package/packages/identity/src/frontend/auth-portal/pages/signup.html +5 -5
- package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
- package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +6 -37
- package/packages/identity/src/index.js +28 -1
- package/packages/identity/src/migrations/README.md +23 -23
- package/packages/identity/src/oauth/README.md +1 -1
- package/packages/identity/src/oauth/credentials.js +10 -11
- package/packages/identity/src/oauth/google-desktop-exchange.js +195 -27
- package/packages/identity/src/oauth/iam-platform.js +21 -9
- package/packages/identity/src/oauth/native-handoff.js +136 -0
- package/packages/identity/src/providers/chatgpt/headers.js +65 -0
- package/packages/identity/src/providers/chatgpt/index.js +86 -0
- package/packages/identity/src/providers/chatgpt/mapper.js +43 -0
- package/packages/identity/src/providers/chatgpt/paths.js +45 -0
- package/packages/identity/src/providers/github/oauth.js +1 -2
- package/packages/identity/src/providers/github/profile.js +16 -2
- package/packages/identity/src/providers/index.js +11 -3
- package/packages/identity/src/server/identity-service.js +2 -1
- package/packages/identity/src/server/worker-router.js +71 -18
- package/packages/identity/tests/chatgpt-provider.test.mjs +75 -0
- package/packages/identity/tests/google-desktop-identity-login.test.mjs +210 -0
- package/packages/identity/tests/identity-init-scaffold.test.mjs +15 -4
- package/packages/identity/tests/lane1-identity-store-parity.test.mjs +527 -0
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +175 -0
- package/packages/identity/tests/native-oauth-handoff.test.mjs +292 -0
- package/packages/identity/tests/oauth-credentials.test.mjs +4 -4
- package/packages/identity/tests/preview-auth-portal.test.mjs +4 -2
- package/packages/identity/tests/session-routes-policy.test.mjs +13 -1
- package/packages/identity/tests/worker-runtime-boundary.test.mjs +11 -0
- package/packages/providers/completeful/package.json +7 -2
- package/packages/theme-church-site/package.json +17 -6
- package/packages/theme-church-site/src/harvest.json +4 -2
- package/packages/theme-church-site/src/index.js +7 -3
- package/packages/theme-church-site/test/theme.test.mjs +4 -2
- package/packages/theme-companions-site/package.json +17 -6
- package/packages/theme-companions-site/src/harvest.json +4 -2
- package/packages/theme-companions-site/src/index.js +7 -3
- package/packages/theme-companions-site/test/theme.test.mjs +4 -2
- package/packages/theme-floors-site/package.json +17 -6
- package/packages/theme-floors-site/src/harvest.json +4 -2
- package/packages/theme-floors-site/src/index.js +7 -3
- package/packages/theme-floors-site/test/theme.test.mjs +4 -2
- package/packages/theme-fuelnfree-site/package.json +17 -6
- package/packages/theme-fuelnfree-site/src/harvest.json +4 -2
- package/packages/theme-fuelnfree-site/src/index.js +7 -3
- package/packages/theme-fuelnfree-site/test/theme.test.mjs +4 -2
- package/packages/theme-handyman-site/package.json +17 -6
- package/packages/theme-handyman-site/src/harvest.json +4 -2
- package/packages/theme-handyman-site/src/index.js +7 -3
- package/packages/theme-handyman-site/test/theme.test.mjs +4 -2
- package/packages/theme-insurance-site/package.json +17 -6
- package/packages/theme-insurance-site/src/harvest.json +4 -2
- package/packages/theme-insurance-site/src/index.js +7 -3
- package/packages/theme-insurance-site/test/theme.test.mjs +4 -2
- package/packages/theme-scenes/README.md +1 -1
- package/packages/theme-scenes/package.json +4 -3
- package/packages/theme-scenes/src/registry.js +187 -0
- package/packages/theme-shinshu-site/package.json +17 -6
- package/packages/theme-shinshu-site/src/harvest.json +4 -2
- package/packages/theme-shinshu-site/src/index.js +7 -3
- package/packages/theme-shinshu-site/test/theme.test.mjs +4 -2
- package/packages/work-graph/package.json +14 -4
- package/protocol/FILEMETA_V1.md +2 -2
- package/protocol/capabilities/manifest.json +1 -1
- package/protocol/database/agentsam.schema-pack.v1.schema.json +72 -0
- package/protocol/presets/catalog.json +2 -2
- package/protocol/theme-refinery/lineage-registry.json +105 -0
- package/protocol/theme-refinery/product-metadata.schema.json +21 -1
- package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
- package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
- package/python/tests/test_repository_intelligence.py +30 -0
- package/src/cli/command-catalog.js +48 -5
- package/src/cli/dispatch.js +1 -0
- package/src/cli.js +20 -1
- package/src/cloudflare/runtime-status.js +2 -1
- package/src/commands/autorag.js +67 -13
- package/src/commands/cheat-sheet.js +29 -4
- package/src/commands/codebaseindex.js +45 -2
- package/src/commands/goap-world.js +134 -0
- package/src/commands/goap.js +11 -4
- package/src/commands/knowledge.js +59 -2
- package/src/commands/machine-binary.js +109 -0
- package/src/commands/machine-runtime.js +266 -0
- package/src/commands/machine.js +208 -0
- package/src/commands/package.js +530 -0
- package/src/commands/plan-ledger.js +370 -0
- package/src/commands/plan.js +183 -0
- package/src/commands/security.js +67 -4
- package/src/commands/setup.js +33 -16
- package/src/commands/skill.js +78 -17
- package/src/commands/status.js +8 -1
- package/src/features/resolve.js +1 -0
- package/src/knowledge/engine.js +21 -2
- package/src/knowledge/runtime-discovery.js +127 -0
- package/src/knowledge/source.js +1 -1
- package/src/lib/identity-scaffold.js +53 -13
- package/src/lib/setup/recipes.js +1 -1
- package/src/lib/slash-commands.js +1 -1
- package/src/local/runtime-store.js +24 -2
- package/src/local/sqlite.js +17 -0
- package/src/models/discovery.js +40 -22
- package/src/models/inventory-core.d.ts +105 -0
- package/src/models/inventory-core.js +54 -6
- package/src/sam/operations/package-audit.js +41 -0
- package/src/sam/seed.js +2 -0
- package/src/security/logs.js +3 -0
- package/src/ui/cli/help.js +41 -0
- package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +0 -145
- package/test/account-session.test.mjs +0 -101
- package/test/agent-capabilities.test.mjs +0 -67
- package/test/app-authority-context.test.mjs +0 -32
- package/test/app-building-skills.test.mjs +0 -61
- package/test/apps-scaffold-contract.test.mjs +0 -114
- package/test/blender-cad.test.mjs +0 -146
- package/test/cad-docker.test.mjs +0 -96
- package/test/capabilities.test.mjs +0 -133
- package/test/cli/api-key-env-whoami.test.mjs +0 -129
- package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
- package/test/cli/eval-live.test.mjs +0 -219
- package/test/cli/go.test.mjs +0 -128
- package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
- package/test/cli/mcp-client.test.mjs +0 -256
- package/test/cli/preferences-runtime.test.mjs +0 -11
- package/test/cli/runtime-persist.test.mjs +0 -56
- package/test/cli/runtime-ui.test.mjs +0 -141
- package/test/cli/rust-command.test.mjs +0 -21
- package/test/cli/skill-npm-and-env.test.mjs +0 -52
- package/test/cli/status-actions.test.mjs +0 -88
- package/test/cli/wireframes-go-registry.test.mjs +0 -139
- package/test/cli-preferences.test.mjs +0 -46
- package/test/cloudflare-connector.test.mjs +0 -93
- package/test/cloudflare-runtime.test.mjs +0 -82
- package/test/context.test.mjs +0 -159
- package/test/credentials-audit.test.mjs +0 -113
- package/test/deploy-health-scan.test.mjs +0 -95
- package/test/deploy-receipt.test.mjs +0 -91
- package/test/dockerize.test.mjs +0 -93
- package/test/error-diagnostics.test.mjs +0 -124
- package/test/eval-context.test.mjs +0 -37
- package/test/execution-approvals.test.mjs +0 -27
- package/test/fixtures/cad/courtyard-house.json +0 -208
- package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
- package/test/gcloud-auth.test.mjs +0 -111
- package/test/go/build-source-identity.test.mjs +0 -31
- package/test/go/cloudflare-probe.test.mjs +0 -317
- package/test/go/distribution.test.mjs +0 -28
- package/test/google-cloud-connection.test.mjs +0 -83
- package/test/google-cloud-inventory.test.mjs +0 -64
- package/test/indexing-provider.test.mjs +0 -29
- package/test/init-options.test.mjs +0 -35
- package/test/integration/ai-access-onboarding.test.mjs +0 -47
- package/test/integration/app-command.test.mjs +0 -85
- package/test/integration/cad-discovery.test.mjs +0 -158
- package/test/integration/cad-docker-executor.test.mjs +0 -249
- package/test/integration/cad-execution.test.mjs +0 -184
- package/test/integration/cad-project-app.test.mjs +0 -31
- package/test/integration/cad-project-d1.test.mjs +0 -25
- package/test/integration/cad-project-native.test.mjs +0 -24
- package/test/integration/cad-project-workflow.test.mjs +0 -9
- package/test/integration/cad-project.test.mjs +0 -85
- package/test/integration/cli-help.test.mjs +0 -41
- package/test/integration/cms-app-scaffold.test.mjs +0 -71
- package/test/integration/cms-site-tenancy-contract.test.mjs +0 -257
- package/test/integration/codebaseindex-ingest.test.mjs +0 -214
- package/test/integration/core-client.integration.test.mjs +0 -55
- package/test/integration/error-runtime-rpc.test.mjs +0 -71
- package/test/integration/features-resolve.test.mjs +0 -147
- package/test/integration/icon-registry.test.mjs +0 -67
- package/test/integration/ingest-discover-models.test.mjs +0 -30
- package/test/integration/inspect-path-cli.test.mjs +0 -46
- package/test/integration/install-script.test.mjs +0 -110
- package/test/integration/inventory-core.test.mjs +0 -53
- package/test/integration/inventory-evidence.test.mjs +0 -125
- package/test/integration/knowledge-rpc.test.mjs +0 -112
- package/test/integration/local-fs.test.mjs +0 -113
- package/test/integration/merkle-cli.test.mjs +0 -61
- package/test/integration/merkle-persistence-identity.test.mjs +0 -48
- package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
- package/test/integration/provider-env-cli.test.mjs +0 -50
- package/test/integration/provider-factory.test.mjs +0 -197
- package/test/integration/repository-company-graph.test.mjs +0 -90
- package/test/integration/runtime-migrations.test.mjs +0 -87
- package/test/integration/runtime-status.integration.test.mjs +0 -212
- package/test/integration/sam-activity-recovery.test.mjs +0 -147
- package/test/integration/sam-decision.test.mjs +0 -584
- package/test/integration/sam-kernel.test.mjs +0 -99
- package/test/integration/sam-planning-astar.test.mjs +0 -279
- package/test/integration/scaffold-cloudflare.test.mjs +0 -46
- package/test/integration/skill-runtime.test.mjs +0 -240
- package/test/integration/storage-architecture.test.mjs +0 -154
- package/test/integration/store-discovery.test.mjs +0 -44
- package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
- package/test/integration/terminal-exec.integration.test.mjs +0 -86
- package/test/integration/tool-runtime.test.mjs +0 -124
- package/test/integration/tool-schema.test.mjs +0 -59
- package/test/jr-dev-skill.test.mjs +0 -26
- package/test/knowledge-context-pack.test.mjs +0 -19
- package/test/knowledge-postgres.test.mjs +0 -40
- package/test/knowledge-service.test.mjs +0 -110
- package/test/knowledge.test.mjs +0 -206
- package/test/live/terminal-transport.live.test.mjs +0 -24
- package/test/local-sessions.test.mjs +0 -57
- package/test/local-studio-deploy.test.mjs +0 -83
- package/test/loopback-oauth.test.mjs +0 -53
- package/test/merkle-render.test.mjs +0 -31
- package/test/mini.test.mjs +0 -140
- package/test/model-catalog.test.mjs +0 -70
- package/test/models.test.mjs +0 -309
- package/test/npm10-lock.test.mjs +0 -29
- package/test/ollama.test.mjs +0 -137
- package/test/open-url.test.mjs +0 -64
- package/test/openai-responses.test.mjs +0 -155
- package/test/portable-context.test.mjs +0 -94
- package/test/project-config.test.mjs +0 -81
- package/test/project-rules.test.mjs +0 -44
- package/test/provider-credentials.test.mjs +0 -106
- package/test/rehydrate.test.mjs +0 -25
- package/test/release-hygiene.test.mjs +0 -42
- package/test/repository-snapshot-view.test.mjs +0 -112
- package/test/responses-runner.test.mjs +0 -465
- package/test/runtime-activity.test.mjs +0 -98
- package/test/sdk-worker-contract.test.mjs +0 -72
- package/test/security.test.mjs +0 -252
- package/test/setup-planner.test.mjs +0 -74
- package/test/setup-runtime.test.mjs +0 -51
- package/test/shell.test.mjs +0 -281
- package/test/skills.test.mjs +0 -22
- package/test/smoke.mjs +0 -122
- package/test/telemetry.test.mjs +0 -79
- package/test/terminal/local-pty.mock.test.mjs +0 -153
- package/test/terminal-machine-identity.test.mjs +0 -88
- package/test/theme-portability.test.mjs +0 -14
- package/test/tools-search.test.mjs +0 -73
- package/test/unit/website-assets-bindings.test.mjs +0 -60
- package/test/whoami-resume.test.mjs +0 -157
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import test from 'node:test';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
createToolExecutor,
|
|
6
|
-
createToolRegistry,
|
|
7
|
-
} from '../../src/tools/index.js';
|
|
8
|
-
import {
|
|
9
|
-
COMPLETEFUL_TOOL_DEFINITIONS,
|
|
10
|
-
createCompletefulClient,
|
|
11
|
-
createCompletefulProviderAdapter,
|
|
12
|
-
} from '../../packages/providers/completeful/src/index.js';
|
|
13
|
-
|
|
14
|
-
test('tool runtime owns idempotency, redacts durable receipts, and emits safe events', async () => {
|
|
15
|
-
let captured = null;
|
|
16
|
-
const client = createCompletefulClient({
|
|
17
|
-
apiKey: 'capp_test_example',
|
|
18
|
-
fetchImpl: async (url, init) => {
|
|
19
|
-
captured = { url, init };
|
|
20
|
-
return new Response(
|
|
21
|
-
JSON.stringify({
|
|
22
|
-
id: 'ord_1',
|
|
23
|
-
email: 'customer@example.com',
|
|
24
|
-
shipping_address: { line1: 'private street' },
|
|
25
|
-
notes: 'private note',
|
|
26
|
-
}),
|
|
27
|
-
{ status: 201, headers: { 'x-request-id': 'req_order_1' } },
|
|
28
|
-
);
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const registry = createToolRegistry({
|
|
33
|
-
tools: COMPLETEFUL_TOOL_DEFINITIONS,
|
|
34
|
-
adapters: [createCompletefulProviderAdapter(client)],
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const recorded = [];
|
|
38
|
-
const observed = [];
|
|
39
|
-
let sequence = 0;
|
|
40
|
-
const executor = createToolExecutor({
|
|
41
|
-
registry,
|
|
42
|
-
makeId: (prefix) => `${prefix}_test_${++sequence}`,
|
|
43
|
-
now: (() => {
|
|
44
|
-
let value = 1_800_000_000_000;
|
|
45
|
-
return () => ++value;
|
|
46
|
-
})(),
|
|
47
|
-
recordReceipt: (receipt) => recorded.push(receipt),
|
|
48
|
-
onEvent: (event) => observed.push(event),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const result = await executor.execute({
|
|
52
|
-
toolKey: 'completeful.order.create',
|
|
53
|
-
accountId: 'acct_1',
|
|
54
|
-
correlationId: 'corr_1',
|
|
55
|
-
input: {
|
|
56
|
-
shop_id: 'shop_1',
|
|
57
|
-
body: {
|
|
58
|
-
shipping_address: { line1: 'private street' },
|
|
59
|
-
email: 'customer@example.com',
|
|
60
|
-
notes: 'private note',
|
|
61
|
-
line_items: [{ product_id: 'prod_1', quantity: 1 }],
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
assert.equal(result.ok, true);
|
|
67
|
-
assert.equal(result.output.email, 'customer@example.com');
|
|
68
|
-
assert.equal(captured.init.headers.get('Idempotency-Key'), result.invocation.id);
|
|
69
|
-
assert.equal(result.receipt.input.body.email, '[REDACTED]');
|
|
70
|
-
assert.equal(result.receipt.input.body.shipping_address, '[REDACTED]');
|
|
71
|
-
assert.equal(result.receipt.output.email, '[REDACTED]');
|
|
72
|
-
assert.equal(result.receipt.output.shipping_address, '[REDACTED]');
|
|
73
|
-
assert.equal(recorded.length, 1);
|
|
74
|
-
assert.equal(observed.length, 1);
|
|
75
|
-
assert.equal(observed[0].eventKey, 'completeful.order.created');
|
|
76
|
-
assert.equal(observed[0].payload.output.email, '[REDACTED]');
|
|
77
|
-
assert.equal(observed[0].causationId, result.invocation.id);
|
|
78
|
-
assert.equal(observed[0].correlationId, 'corr_1');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('tool runtime converts provider errors into the canonical AgentSam envelope', async () => {
|
|
82
|
-
const client = createCompletefulClient({
|
|
83
|
-
apiKey: 'capp_test_example',
|
|
84
|
-
fetchImpl: async () =>
|
|
85
|
-
new Response(
|
|
86
|
-
JSON.stringify({
|
|
87
|
-
error: 'too many requests',
|
|
88
|
-
code: 'rate_limited',
|
|
89
|
-
request_id: 'req_rate',
|
|
90
|
-
}),
|
|
91
|
-
{ status: 429 },
|
|
92
|
-
),
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const registry = createToolRegistry({
|
|
96
|
-
tools: COMPLETEFUL_TOOL_DEFINITIONS,
|
|
97
|
-
adapters: [createCompletefulProviderAdapter(client)],
|
|
98
|
-
});
|
|
99
|
-
const executor = createToolExecutor({
|
|
100
|
-
registry,
|
|
101
|
-
makeId: (prefix) => `${prefix}_failure`,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
const result = await executor.execute({
|
|
105
|
-
toolKey: 'completeful.catalog.list',
|
|
106
|
-
input: { limit: 1 },
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
assert.equal(result.ok, false);
|
|
110
|
-
assert.equal(result.error.reason, 'provider_rate_limited');
|
|
111
|
-
assert.equal(result.error.code, 'RESOURCE_EXHAUSTED');
|
|
112
|
-
assert.equal(result.error.provider, 'completeful');
|
|
113
|
-
assert.equal(result.error.provider_code, 'rate_limited');
|
|
114
|
-
assert.equal(result.error.request_id, 'req_rate');
|
|
115
|
-
assert.equal(result.receipt.status, 'failed');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('registry rejects duplicate tool keys instead of silently shadowing definitions', () => {
|
|
119
|
-
const definition = COMPLETEFUL_TOOL_DEFINITIONS[0];
|
|
120
|
-
assert.throws(
|
|
121
|
-
() => createToolRegistry({ tools: [definition, definition] }),
|
|
122
|
-
/duplicate tool definition/,
|
|
123
|
-
);
|
|
124
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { compileToolSchema, restoreOptionalArguments } from '../../src/providers/tool-schema.js';
|
|
4
|
-
import { createCapabilityAdapter } from '../../src/agent/capability-adapter.js';
|
|
5
|
-
import { createOpenAIResponsesAdapter } from '../../src/providers/openai-responses.js';
|
|
6
|
-
import { createGeminiGenerateContentAdapter } from '../../src/providers/gemini-generate-content.js';
|
|
7
|
-
|
|
8
|
-
const canonical = { $schema: 'https://json-schema.org/draft/2020-12/schema', $id: 'sample', type: 'object', properties: {
|
|
9
|
-
text: { type: 'string' }, rows: { type: 'array', items: { type: 'object', properties: { label: { type: 'string', enum: ['x'] } } } },
|
|
10
|
-
additionalProperties: { type: 'string' },
|
|
11
|
-
}, required: ['text'] };
|
|
12
|
-
|
|
13
|
-
test('strict compiler recursively closes objects and makes omitted fields nullable without mutating canonical input', () => {
|
|
14
|
-
const original = structuredClone(canonical);
|
|
15
|
-
const { providerSchema: s } = compileToolSchema({ provider: 'openai', canonicalSchema: canonical });
|
|
16
|
-
assert.equal(s.additionalProperties, false);
|
|
17
|
-
assert.deepEqual(s.required, ['text', 'rows', 'additionalProperties']);
|
|
18
|
-
assert.equal(s.properties.rows.anyOf[0].items.additionalProperties, false);
|
|
19
|
-
assert.deepEqual(s.properties.rows.anyOf[0].items.required, ['label']);
|
|
20
|
-
assert.deepEqual(s.properties.rows.anyOf[0].items.properties.label.anyOf, [{ type: 'string', enum: ['x'] }, { type: 'null' }]);
|
|
21
|
-
assert.deepEqual(canonical, original);
|
|
22
|
-
assert.deepEqual(restoreOptionalArguments({ text: 'x', rows: [{ label: null }], additionalProperties: null }, canonical), { text: 'x', rows: [{}] });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('all executable capability schemas compile for both providers, including actual knowledge.search arguments', () => {
|
|
26
|
-
for (const descriptor of createCapabilityAdapter().toolDescriptors()) {
|
|
27
|
-
for (const provider of ['openai', 'gemini']) assert.ok(compileToolSchema({ provider, canonicalSchema: descriptor.input_schema, strict: descriptor.strict !== false, name: descriptor.name }).hash);
|
|
28
|
-
if (descriptor.name === 'knowledge.search') assert.equal(descriptor.input_schema.properties.text.type, 'string');
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test('bad schemas fail before provider fetch, with actionable paths', async () => {
|
|
33
|
-
for (const schema of [
|
|
34
|
-
{ type: 'object', properties: {}, required: ['missing'] },
|
|
35
|
-
{ type: 'object', properties: { x: { $ref: 'https://remote/schema' } } },
|
|
36
|
-
{ type: 'object', properties: { x: { type: 'array' } } },
|
|
37
|
-
{ type: 'object', properties: { x: { type: 'invalid' } } },
|
|
38
|
-
]) {
|
|
39
|
-
let requests = 0;
|
|
40
|
-
const adapter = createOpenAIResponsesAdapter({ apiKey: 'test', fetchImpl: async () => { requests++; } });
|
|
41
|
-
await assert.rejects(adapter.create({ model: 'gpt-6-astra', input: 'test', tools: [{ type: 'function', name: 'broken', parameters: schema }] }), /tool_schema_invalid:openai:broken:/);
|
|
42
|
-
assert.equal(requests, 0);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('Gemini uses JSON Schema declaration field and preserves canonical optionality', async () => {
|
|
47
|
-
let body;
|
|
48
|
-
const adapter = createGeminiGenerateContentAdapter({ apiKey: 'test', fetchImpl: async (_, init) => {
|
|
49
|
-
body = JSON.parse(init.body);
|
|
50
|
-
return { ok: true, json: async () => ({ candidates: [{ content: { role: 'model', parts: [{ text: 'ok' }] } }] }) };
|
|
51
|
-
} });
|
|
52
|
-
await adapter.create({ modelRecord: { provider: 'gemini', provider_model_id: 'fixture' }, input: 'test', tools: [{ name: 'sample', parameters: canonical }] });
|
|
53
|
-
const declaration = body.tools[0].functionDeclarations[0];
|
|
54
|
-
assert.equal(declaration.parameters, undefined);
|
|
55
|
-
assert.equal(declaration.parametersJsonSchema.$schema, undefined);
|
|
56
|
-
assert.equal(declaration.parametersJsonSchema.$id, undefined);
|
|
57
|
-
assert.deepEqual(declaration.parametersJsonSchema.required, ['text']);
|
|
58
|
-
assert.equal(declaration.parametersJsonSchema.properties.additionalProperties.type, 'string');
|
|
59
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import test from 'node:test';
|
|
5
|
-
|
|
6
|
-
const root = path.resolve(import.meta.dirname, '..');
|
|
7
|
-
const skill = path.join(root, 'skills', 'agentsam-jr-dev', 'SKILL.md');
|
|
8
|
-
const fundamentals = path.join(root, 'skills', 'agentsam-jr-dev', 'references', 'web-application-fundamentals.md');
|
|
9
|
-
const logic = path.join(root, 'skills', 'agentsam-jr-dev', 'references', 'real-application-logic.md');
|
|
10
|
-
|
|
11
|
-
test('agentsam-jr-dev ships as a portable skill with depth references', () => {
|
|
12
|
-
for (const file of [skill, fundamentals, logic]) {
|
|
13
|
-
assert.equal(fs.existsSync(file), true, `${file} must exist`);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const text = fs.readFileSync(skill, 'utf8');
|
|
17
|
-
assert.match(text, /name: agentsam-jr-dev/);
|
|
18
|
-
assert.match(text, /Inspect before teaching repo-specific facts/);
|
|
19
|
-
assert.match(text, /Real application logic is the standard/);
|
|
20
|
-
assert.match(text, /Never invent a repo architecture/);
|
|
21
|
-
assert.match(text, /frontend owns presentation/);
|
|
22
|
-
assert.match(text, /backend owns trusted execution/);
|
|
23
|
-
|
|
24
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
25
|
-
assert.ok(pkg.files.includes('skills'), 'root npm package must include portable skills');
|
|
26
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import test from 'node:test';
|
|
3
|
-
import { createContextPack } from '../src/knowledge/context-pack.js';
|
|
4
|
-
|
|
5
|
-
test('knowledge ContextPack includes a measurable selection receipt', () => {
|
|
6
|
-
const pack = createContextPack({
|
|
7
|
-
queryId: 'q1',
|
|
8
|
-
query: { text: 'where is auth?', top_k: 2, token_budget: 2000 },
|
|
9
|
-
hits: [{ ref: 'file:a', content: 'abcd' }, { ref: 'file:b', content: '12345678' }],
|
|
10
|
-
diagnostics: { sources_considered: 7, sources_deferred: 5 },
|
|
11
|
-
});
|
|
12
|
-
assert.deepEqual(pack.receipt, {
|
|
13
|
-
chars: 12,
|
|
14
|
-
estimated_tokens: 3,
|
|
15
|
-
sources_considered: 7,
|
|
16
|
-
sources_included: 2,
|
|
17
|
-
sources_deferred: 5,
|
|
18
|
-
});
|
|
19
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { PGlite } from '@electric-sql/pglite';
|
|
7
|
-
import { vector } from '@electric-sql/pglite-pgvector';
|
|
8
|
-
import { createPostgresStore, defaultConfig, runIndex, retrieve, scopeKey } from '../src/knowledge/index.js';
|
|
9
|
-
|
|
10
|
-
test('real Postgres/pgvector schema, exact retrieval, profile isolation and publication rollback', async t => {
|
|
11
|
-
const db = new PGlite({ extensions: { vector } });
|
|
12
|
-
// PGlite exposes the same parameterized SQL execution; exec supports DDL batches.
|
|
13
|
-
const store = createPostgresStore({ query: (sql, params) => params ? db.query(sql, params) : db.exec(sql).then(results => results.at(-1)), end: () => db.close() });
|
|
14
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-pg-'));
|
|
15
|
-
t.after(async () => { await store.close(); fs.rmSync(root, { recursive: true, force: true }); });
|
|
16
|
-
await store.setup(); await store.setup();
|
|
17
|
-
fs.writeFileSync(path.join(root, 'math.ts'), 'export function add(a: number, b: number) { return a + b; }\nexport const name = "math";');
|
|
18
|
-
const config = defaultConfig();
|
|
19
|
-
config.embedding = { provider: 'fixture', model: 'vector-test', revision: '1', dimensions: 3, parameters: {} };
|
|
20
|
-
const embedder = { async embed(text) { return text.includes('add') ? [1, 0, 0] : [0, 1, 0]; } };
|
|
21
|
-
const first = await runIndex({ root, config, store, embedder, embed: true });
|
|
22
|
-
const result = await retrieve({ config, store, embedder, text: 'add', semantic: true });
|
|
23
|
-
assert.equal(result.hits[0].metadata.symbol, 'add'); assert.equal(result.hits[0].score, 1);
|
|
24
|
-
assert.equal((await db.query('SELECT count(*)::int AS n FROM agentsam_knowledge.cache WHERE embedding IS NOT NULL')).rows[0].n, 2);
|
|
25
|
-
assert.equal((await runIndex({ root, config, store, embedder, embed: true })).embedding_inputs, 0);
|
|
26
|
-
// A different-dimensional profile in the same table must not break retrieval.
|
|
27
|
-
await store.cachePut('foreign:vector:other', [1, 0, 0, 0]);
|
|
28
|
-
assert.equal((await retrieve({ config, store, embedder, text: 'add', semantic: true })).hits[0].score, 1);
|
|
29
|
-
const generation = await store.active(scopeKey(config));
|
|
30
|
-
await assert.rejects(store.publish({ ...generation, id: 'bad-cas' }, 'wrong-parent'), /concurrently/);
|
|
31
|
-
assert.equal((await store.active(scopeKey(config))).id, first.generation_id);
|
|
32
|
-
// Force SQL failure after the CAS check; the old generation remains visible.
|
|
33
|
-
await assert.rejects(store.publish(generation, generation.id), /duplicate key/);
|
|
34
|
-
assert.equal((await store.active(scopeKey(config))).id, first.generation_id);
|
|
35
|
-
assert.equal((await store.history(scopeKey(config))).length, 1);
|
|
36
|
-
const observation = { id: 'obs-1', created_at: new Date().toISOString(), data: { files: 1 } };
|
|
37
|
-
await store.observe('customer', observation);
|
|
38
|
-
assert.deepEqual(await store.observations('customer'), [observation]);
|
|
39
|
-
assert.deepEqual(await store.observations('another-customer'), []);
|
|
40
|
-
});
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { DatabaseSync } from 'node:sqlite';
|
|
7
|
-
import { defaultConfig } from '../src/knowledge/config.js';
|
|
8
|
-
import { startKnowledgeService } from '../src/knowledge/service/server.js';
|
|
9
|
-
import { createKnowledgeServiceClient } from '../src/knowledge/service/client.js';
|
|
10
|
-
import { dockerize } from '../src/lib/dockerize.js';
|
|
11
|
-
|
|
12
|
-
async function completed(client, id) {
|
|
13
|
-
for (let i = 0; i < 200; i++) {
|
|
14
|
-
const job = await client.job(id);
|
|
15
|
-
if (['completed', 'failed'].includes(job.status)) { assert.equal(job.status, 'completed', job.error); return job; }
|
|
16
|
-
await new Promise(resolve => setTimeout(resolve, 25));
|
|
17
|
-
}
|
|
18
|
-
throw new Error('Job did not complete.');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
test('service isolates scopes, authenticates, deduplicates, indexes, searches, and preserves restart state', async () => {
|
|
22
|
-
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-service-'));
|
|
23
|
-
const root = path.join(tmp, 'repo'), stateDir = path.join(tmp, 'state');
|
|
24
|
-
fs.mkdirSync(path.join(root, 'src'), { recursive: true });
|
|
25
|
-
fs.writeFileSync(path.join(root, 'src/math.ts'), 'export function add(a: number,b: number) { return a+b; }\n');
|
|
26
|
-
fs.writeFileSync(path.join(root, '.env.json'), '{"password":"must-not-index"}');
|
|
27
|
-
const before = fs.readFileSync(path.join(root, 'src/math.ts'), 'utf8');
|
|
28
|
-
const token = 't'.repeat(64), repositories = { sample: { root, config: defaultConfig({ include: ['src'] }) } };
|
|
29
|
-
let service;
|
|
30
|
-
try {
|
|
31
|
-
service = await startKnowledgeService({ stateDir, repositories, token, port: 0, maxFiles: 1 });
|
|
32
|
-
let baseUrl = `http://127.0.0.1:${service.address.port}`;
|
|
33
|
-
let client = createKnowledgeServiceClient({ baseUrl, token });
|
|
34
|
-
assert.equal((await fetch(baseUrl + '/healthz')).status, 200);
|
|
35
|
-
assert.equal((await fetch(baseUrl + '/v1/repositories')).status, 401);
|
|
36
|
-
await assert.rejects(client.submit({ repository: 'missing', operation: 'index' }), e => e.status === 404);
|
|
37
|
-
await assert.rejects(client.submit({ repository: 'sample', operation: 'index', include: ['.'] }), e => e.status === 403);
|
|
38
|
-
await assert.rejects(client.submit({ repository: 'sample', operation: 'index', include: ['../'] }), e => e.status === 400);
|
|
39
|
-
await assert.rejects(client.submit({ repository: 'sample', operation: 'index', embed: true }), e => e.status === 403);
|
|
40
|
-
const request = { repository: 'sample', operation: 'index' };
|
|
41
|
-
const submitted = await client.submit(request, 'first');
|
|
42
|
-
assert.equal((await client.submit(request, 'first')).id, submitted.id);
|
|
43
|
-
await assert.rejects(client.submit({ ...request, scope: 'other' }, 'first'), e => e.status === 409);
|
|
44
|
-
const first = await completed(client, submitted.id);
|
|
45
|
-
assert.equal(first.result.files, 1); assert.equal(first.result.embedding_inputs, 0);
|
|
46
|
-
assert.equal(first.result.published, true);
|
|
47
|
-
const second = await completed(client, (await client.submit(request)).id);
|
|
48
|
-
assert.equal(second.result.no_change, true); assert.equal(second.result.parsed_files, 0);
|
|
49
|
-
assert.equal(second.result.generation_id, first.result.generation_id);
|
|
50
|
-
fs.writeFileSync(path.join(root, 'src/unindexed.ts'), 'export const later = true;');
|
|
51
|
-
const search = await completed(client, (await client.submit({ repository: 'sample', operation: 'search', query: 'add' })).id);
|
|
52
|
-
assert.match(JSON.stringify(search.result), /src\/math.ts/);
|
|
53
|
-
const narrow = await client.submit({ repository: 'sample', operation: 'search', query: 'add', include: ['src/unindexed.ts'] });
|
|
54
|
-
for (let i = 0; i < 200; i++) {
|
|
55
|
-
const job = await client.job(narrow.id);
|
|
56
|
-
if (job.status === 'failed') { assert.match(job.error, /exceeds the requested scope/); break; }
|
|
57
|
-
if (i === 199) assert.fail('Narrowed scope should fail without leaking broader snapshot contents.');
|
|
58
|
-
await new Promise(resolve => setTimeout(resolve, 25));
|
|
59
|
-
}
|
|
60
|
-
fs.unlinkSync(path.join(root, 'src/unindexed.ts'));
|
|
61
|
-
const plan = await completed(client, (await client.submit({ repository: 'sample', operation: 'plan', embed: true })).id);
|
|
62
|
-
assert.ok(plan.result.embedding_inputs > 0); // Costs can be estimated without credentials.
|
|
63
|
-
await service.close(); service = null;
|
|
64
|
-
// Simulate an interrupted persisted job, as happens on SIGKILL/power loss.
|
|
65
|
-
const db = new DatabaseSync(path.join(stateDir, 'jobs.sqlite'));
|
|
66
|
-
db.prepare("UPDATE jobs SET status='running',result=NULL,attempts=1 WHERE id=?").run(second.id); db.close();
|
|
67
|
-
service = await startKnowledgeService({ stateDir, repositories, token, port: 0 });
|
|
68
|
-
baseUrl = `http://127.0.0.1:${service.address.port}`;
|
|
69
|
-
client = createKnowledgeServiceClient({ baseUrl, token });
|
|
70
|
-
assert.equal((await client.job(first.id)).result.generation_id, first.result.generation_id);
|
|
71
|
-
const recovered = await completed(client, second.id);
|
|
72
|
-
assert.equal(recovered.attempts, 2); assert.equal(recovered.result.no_change, true);
|
|
73
|
-
assert.equal(fs.readFileSync(path.join(root, 'src/math.ts'), 'utf8'), before);
|
|
74
|
-
assert.equal(fs.existsSync(path.join(root, '.agentsam')), false);
|
|
75
|
-
} finally { await service?.close(); fs.rmSync(tmp, { recursive: true, force: true }); }
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test('portable dockerize stages only SDK runtime, preserves identities/tokens, and generates persistent loopback config', async () => {
|
|
79
|
-
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-service-docker-'));
|
|
80
|
-
const root = path.join(tmp, 'customer'); fs.mkdirSync(root);
|
|
81
|
-
fs.writeFileSync(path.join(root, 'customer-secret.js'), 'must not enter build context');
|
|
82
|
-
try {
|
|
83
|
-
const options = { appSlug: 'knowledge-test', repositories: [`customer=${root}`], writeOnly: true };
|
|
84
|
-
const result = await dockerize(tmp, 'knowledge_service', options);
|
|
85
|
-
assert.match(result.plan.files.compose, /127\.0\.0\.1:8792:8792/);
|
|
86
|
-
assert.match(result.plan.files.compose, /unless-stopped/);
|
|
87
|
-
assert.match(result.plan.files.compose, /"read_only":true/);
|
|
88
|
-
const context = path.join(result.written.versionDir, 'context');
|
|
89
|
-
assert.equal(fs.existsSync(path.join(context, 'customer-secret.js')), false);
|
|
90
|
-
assert.equal(fs.existsSync(path.join(context, 'src/knowledge/service/server.js')), true);
|
|
91
|
-
assert.equal(fs.existsSync(path.join(context, 'src/knowledge/service/grpc-server.js')), true);
|
|
92
|
-
assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/knowledge_pb.js')), true);
|
|
93
|
-
assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/knowledge_grpc_pb.js')), true);
|
|
94
|
-
assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/package.json')), true);
|
|
95
|
-
assert.equal(fs.existsSync(path.join(context, 'src/errors/contract.js')), true);
|
|
96
|
-
assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-errors/src/index.js')), true);
|
|
97
|
-
assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-errors/package.json')), true);
|
|
98
|
-
assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-repository/src/merkle/hash.js')), true);
|
|
99
|
-
assert.match(result.plan.files.dockerfile, /COPY packages \.\/packages/);
|
|
100
|
-
assert.equal(fs.existsSync(path.join(context, 'package-lock.json')), true);
|
|
101
|
-
const token = fs.readFileSync(result.tokenFile, 'utf8');
|
|
102
|
-
assert.equal(fs.statSync(result.tokenFile).mode & 0o777, 0o600);
|
|
103
|
-
assert.ok(!JSON.stringify(result.plan).includes(token.trim()));
|
|
104
|
-
const registry = fs.readFileSync(path.join(result.configurationDir, 'repositories.json'), 'utf8');
|
|
105
|
-
await dockerize(tmp, 'knowledge_service', options);
|
|
106
|
-
assert.equal(fs.readFileSync(result.tokenFile, 'utf8'), token);
|
|
107
|
-
assert.equal(fs.readFileSync(path.join(result.configurationDir, 'repositories.json'), 'utf8'), registry);
|
|
108
|
-
await assert.rejects(dockerize(tmp, 'knowledge_service', { ...options, timeoutSeconds: 2 }), /persistent/);
|
|
109
|
-
} finally { fs.rmSync(tmp, { recursive: true, force: true }); }
|
|
110
|
-
});
|
package/test/knowledge.test.mjs
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { execFileSync } from 'node:child_process';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import { defaultConfig, initRepository, readConfig, scopeKey, embeddingProfileId, openSqliteStore, runIndex, planIndex, retrieve, createGeminiEmbedder, KnowledgeClient } from '../src/knowledge/index.js';
|
|
9
|
-
import { inventory, parseSource } from '../src/knowledge/source.js';
|
|
10
|
-
|
|
11
|
-
const cli = fileURLToPath(new URL('../src/cli.js', import.meta.url));
|
|
12
|
-
const write = (root, name, content) => { fs.mkdirSync(path.dirname(path.join(root, name)), { recursive: true }); fs.writeFileSync(path.join(root, name), content); };
|
|
13
|
-
async function fixture(t) {
|
|
14
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-knowledge-'));
|
|
15
|
-
execFileSync('git', ['init', '-q'], { cwd: root });
|
|
16
|
-
write(root, 'src/a.ts', 'export function alpha() { return 1; }\nexport function beta() { return 2; }\n');
|
|
17
|
-
write(root, 'other/b.js', 'export const gamma = 3;\n');
|
|
18
|
-
const config = defaultConfig({ include: ['src'] });
|
|
19
|
-
config.embedding = { provider: 'fixture', model: 'deterministic', revision: '1', dimensions: 3, parameters: {} };
|
|
20
|
-
const store = await openSqliteStore(path.join(root, '.agentsam/knowledge/index.sqlite'));
|
|
21
|
-
let calls = 0;
|
|
22
|
-
const embedder = { async embed(text) { calls++; return [1, text.includes('alpha') ? 1 : 0, text.length / 100]; } };
|
|
23
|
-
t.after(async () => { await store.close(); fs.rmSync(root, { recursive: true, force: true }); });
|
|
24
|
-
return { root, config, store, embedder, count: () => calls };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
test('AST parser observes real syntax, spans and unresolved edges; text is labeled separately', () => {
|
|
28
|
-
const code = `import { read } from './io';\nexport class Reader { value() { return read(); } }\n`;
|
|
29
|
-
const parsed = parseSource('reader.ts', code);
|
|
30
|
-
assert.ok(parsed.symbols.some(s => s.name === 'Reader.value'));
|
|
31
|
-
assert.ok(parsed.edges.some(e => e.kind === 'calls' && e.target === 'read' && e.resolved === false));
|
|
32
|
-
assert.equal(parsed.chunks.map(c => c.content).join(''), code.trimEnd());
|
|
33
|
-
assert.equal(parseSource('schema.sql', 'select 1;').parser, 'text:1');
|
|
34
|
-
assert.throws(() => parseSource('bad.ts', 'export function {'), /bad.ts/);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test('Rust sources survive knowledge inventory and persist in the active SQLite generation', async t => {
|
|
38
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-knowledge-rust-'));
|
|
39
|
-
execFileSync('git', ['init', '-q'], { cwd: root });
|
|
40
|
-
write(root, 'core/src/lib.rs', 'pub fn core_value() -> u32 { 7 }\n');
|
|
41
|
-
write(root, 'worker/src/lib.rs', 'pub fn worker_value() -> u32 { 8 }\n');
|
|
42
|
-
write(root, 'docs/MACHINE-PIPELINE.md', '# Machine pipeline\n');
|
|
43
|
-
write(root, 'target/generated.rs', 'pub fn generated() {}\n');
|
|
44
|
-
|
|
45
|
-
const config = defaultConfig({ include: ['core', 'worker', 'docs'], exclude: ['target'] });
|
|
46
|
-
const store = await openSqliteStore(path.join(root, '.agentsam/knowledge/index.sqlite'));
|
|
47
|
-
t.after(async () => {
|
|
48
|
-
await store.close();
|
|
49
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const files = inventory(root, config.scope);
|
|
53
|
-
assert.ok(files.includes('core/src/lib.rs'));
|
|
54
|
-
assert.ok(files.includes('worker/src/lib.rs'));
|
|
55
|
-
assert.ok(files.includes('docs/MACHINE-PIPELINE.md'));
|
|
56
|
-
assert.equal(files.includes('target/generated.rs'), false);
|
|
57
|
-
|
|
58
|
-
const result = await runIndex({ root, config, store, embed: false });
|
|
59
|
-
assert.equal(result.published, true);
|
|
60
|
-
assert.ok(result.changes.added.includes('core/src/lib.rs'));
|
|
61
|
-
assert.ok(result.changes.added.includes('worker/src/lib.rs'));
|
|
62
|
-
|
|
63
|
-
const generation = await store.getGeneration(scopeKey(config), result.generation_id);
|
|
64
|
-
const persisted = generation.files.map(file => file.path);
|
|
65
|
-
assert.ok(persisted.includes('core/src/lib.rs'));
|
|
66
|
-
assert.ok(persisted.includes('worker/src/lib.rs'));
|
|
67
|
-
assert.ok(persisted.includes('docs/MACHINE-PIPELINE.md'));
|
|
68
|
-
assert.equal(generation.files.find(file => file.path === 'core/src/lib.rs')?.parser, 'text:1');
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('incremental indexing reuses unchanged functions, moves and deletions; old knowledge remains retrievable', async t => {
|
|
72
|
-
const f = await fixture(t), args = { ...f, embed: true };
|
|
73
|
-
const plan = await planIndex(args);
|
|
74
|
-
assert.equal(f.count(), 0); assert.equal(await f.store.active(scopeKey(f.config)), null);
|
|
75
|
-
assert.equal(plan.receipt.embedding_inputs, 2);
|
|
76
|
-
const first = await runIndex(args);
|
|
77
|
-
assert.equal(f.count(), 2);
|
|
78
|
-
const again = await runIndex(args);
|
|
79
|
-
assert.equal(again.published, false); assert.equal(again.parsed_files, 0); assert.equal(f.count(), 2);
|
|
80
|
-
fs.renameSync(path.join(f.root, 'src/a.ts'), path.join(f.root, 'src/moved.ts'));
|
|
81
|
-
const moved = await runIndex(args);
|
|
82
|
-
assert.equal(moved.embedding_inputs, 0); assert.equal(moved.parsed_files, 0); assert.equal(f.count(), 2);
|
|
83
|
-
write(f.root, 'src/moved.ts', 'export function alpha() { return 100; }\nexport function beta() { return 2; }\n');
|
|
84
|
-
assert.equal((await runIndex(args)).embedding_inputs, 1); assert.equal(f.count(), 3);
|
|
85
|
-
const old = await retrieve({ ...f, text: 'alpha', generationId: first.generation_id });
|
|
86
|
-
assert.ok(old.hits.some(h => h.content.includes('return 1;') && h.path === 'src/a.ts' && h.stale));
|
|
87
|
-
fs.unlinkSync(path.join(f.root, 'src/moved.ts'));
|
|
88
|
-
assert.deepEqual((await runIndex(args)).changes.removed, ['src/moved.ts']);
|
|
89
|
-
assert.equal((await retrieve({ ...f, text: 'alpha' })).hits.length, 0);
|
|
90
|
-
assert.equal((await f.store.history(scopeKey(f.config))).length, 4);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test('scope and repository isolation; profile changes cannot silently reuse vectors', async t => {
|
|
94
|
-
const f = await fixture(t);
|
|
95
|
-
await runIndex({ ...f, embed: true });
|
|
96
|
-
const other = structuredClone(f.config); other.scope = { name: 'other', include: ['other'], exclude: [] };
|
|
97
|
-
await runIndex({ ...f, config: other, embed: true });
|
|
98
|
-
assert.equal((await f.store.active(scopeKey(f.config))).files[0].path, 'src/a.ts');
|
|
99
|
-
const changed = structuredClone(f.config); changed.embedding.revision = '2';
|
|
100
|
-
assert.notEqual(embeddingProfileId(changed.embedding), embeddingProfileId(f.config.embedding));
|
|
101
|
-
assert.equal((await planIndex({ ...f, config: changed, embed: true })).receipt.embedding_inputs, 2);
|
|
102
|
-
await assert.rejects(retrieve({ ...f, config: changed, text: 'alpha', semantic: true }), /different embedding profile/);
|
|
103
|
-
const foreign = structuredClone(f.config); foreign.repository_id = 'another-repo';
|
|
104
|
-
assert.equal((await planIndex({ ...f, config: foreign, embed: true })).receipt.embedding_inputs, 2);
|
|
105
|
-
const wider = structuredClone(f.config); wider.scope.include.push('other');
|
|
106
|
-
assert.equal((await planIndex({ ...f, config: wider, embed: true })).receipt.files, 2);
|
|
107
|
-
assert.equal((await planIndex({ ...f, config: wider, embed: true })).receipt.embedding_inputs, 0);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('budgets, invalid vectors and concurrent changes preserve the active generation and useful cached work', async t => {
|
|
111
|
-
const f = await fixture(t);
|
|
112
|
-
const initial = await runIndex(f);
|
|
113
|
-
await assert.rejects(runIndex({ ...f, embed: true, maxInputs: 0 }), /budget/);
|
|
114
|
-
assert.equal(f.count(), 0);
|
|
115
|
-
let requests = 0;
|
|
116
|
-
await assert.rejects(runIndex({ ...f, embed: true, embedder: { async embed() { if (++requests === 2) throw new Error('503'); return [1, 0, 0]; } } }), /503/);
|
|
117
|
-
assert.equal((await f.store.active(scopeKey(f.config))).id, initial.generation_id);
|
|
118
|
-
assert.equal((await planIndex({ ...f, embed: true })).receipt.embedding_inputs, 1);
|
|
119
|
-
await assert.rejects(runIndex({ ...f, embed: true, embedder: { async embed() { return [NaN]; } } }), /finite values/);
|
|
120
|
-
assert.equal((await f.store.active(scopeKey(f.config))).id, initial.generation_id);
|
|
121
|
-
const resumed = await runIndex({ ...f, embed: true }); assert.equal(resumed.embedding_inputs, 1);
|
|
122
|
-
write(f.root, 'src/a.ts', 'export function alpha() { return 33; }');
|
|
123
|
-
await assert.rejects(runIndex({ ...f, embed: true, embedder: { async embed() { write(f.root, 'src/a.ts', 'export function alpha() { return 44; }'); return [1, 0, 0]; } } }), /Repository changed/);
|
|
124
|
-
assert.equal((await f.store.active(scopeKey(f.config))).id, resumed.generation_id);
|
|
125
|
-
const current = await f.store.active(scopeKey(f.config));
|
|
126
|
-
await assert.rejects(f.store.publish({ ...current, id: 'race' }, initial.generation_id), /concurrently/);
|
|
127
|
-
assert.equal((await f.store.active(scopeKey(f.config))).id, resumed.generation_id);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test('source safety and setup preserve repository files; read-only plan creates no database', async t => {
|
|
131
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-adopt-'));
|
|
132
|
-
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
133
|
-
execFileSync('git', ['init', '-q'], { cwd: root });
|
|
134
|
-
write(root, 'package.json', '{"name":"keep-this"}\n');
|
|
135
|
-
write(root, '.env.js', 'SECRET'); write(root, 'src/real.ts', 'export const real = 1;');
|
|
136
|
-
write(root, '.gitignore', 'ignored/\n'); write(root, 'ignored/hidden.ts', 'export const hidden = 1;');
|
|
137
|
-
fs.symlinkSync(path.join(root, '.env.js'), path.join(root, 'src/link.ts'));
|
|
138
|
-
const initial = fs.readFileSync(path.join(root, 'package.json'), 'utf8');
|
|
139
|
-
const output = execFileSync(process.execPath, [cli, 'init', '--yes', '--include', 'src'], { cwd: root, encoding: 'utf8' });
|
|
140
|
-
assert.equal(JSON.parse(output).storage, 'sqlite');
|
|
141
|
-
assert.equal(fs.readFileSync(path.join(root, 'package.json'), 'utf8'), initial);
|
|
142
|
-
assert.throws(() => initRepository(root), /EEXIST/);
|
|
143
|
-
const plan = JSON.parse(execFileSync(process.execPath, [cli, 'index', 'plan'], { cwd: root, encoding: 'utf8' }));
|
|
144
|
-
assert.equal(plan.files, 1); assert.deepEqual(plan.skipped, ['src/link.ts']);
|
|
145
|
-
assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge/index.sqlite')), false);
|
|
146
|
-
const all = readConfig(root); all.scope.include = ['.'];
|
|
147
|
-
const paths = (await planIndex({ root, config: all })).files.map(f => f.path);
|
|
148
|
-
assert.ok(!paths.includes('.env.js')); assert.ok(!paths.includes('ignored/hidden.ts'));
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test('index and search derive safe local defaults when knowledge.json is absent', async t => {
|
|
152
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-configless-'));
|
|
153
|
-
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
154
|
-
execFileSync('git', ['init', '-q'], { cwd: root });
|
|
155
|
-
execFileSync('git', ['remote', 'add', 'origin', 'git@github.com:ExampleOrg/ConfiglessRepo.git'], { cwd: root });
|
|
156
|
-
write(root, 'src/real.ts', 'export function configlessSymbol() { return 7; }\n');
|
|
157
|
-
const run = args => JSON.parse(execFileSync(process.execPath, [cli, ...args], { cwd: root, encoding: 'utf8' }));
|
|
158
|
-
assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge.json')), false);
|
|
159
|
-
const plan = run(['index', 'plan']);
|
|
160
|
-
assert.ok(plan.files >= 1); assert.equal(plan.embedding_inputs, 0);
|
|
161
|
-
assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge.json')), false);
|
|
162
|
-
assert.equal(run(['index', 'run']).published, true);
|
|
163
|
-
assert.equal(fs.existsSync(path.join(root, '.agentsam/knowledge.json')), false);
|
|
164
|
-
assert.equal(run(['search', 'configlessSymbol']).hits[0].path, 'src/real.ts');
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test('two independent repositories work through the same CLI and exported package', async t => {
|
|
168
|
-
for (const name of ['customer-a', 'customer-b']) {
|
|
169
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), name));
|
|
170
|
-
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
171
|
-
write(root, 'lib/tool.js', `export function ${name.replace('-', '_')}() { return 1; }`);
|
|
172
|
-
const run = args => JSON.parse(execFileSync(process.execPath, [cli, ...args], { cwd: root, encoding: 'utf8' }));
|
|
173
|
-
run(['init', '.', '--yes', '--include', 'lib']);
|
|
174
|
-
assert.equal(run(['index', 'run']).published, true);
|
|
175
|
-
assert.equal(run(['index', 'run']).no_change, true);
|
|
176
|
-
assert.equal(run(['search', name.replace('-', '_')]).hits[0].path, 'lib/tool.js');
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test('Gemini sends task prefixes and configured dimensions, retries transient responses, and rejects unsupported profiles', async () => {
|
|
181
|
-
const requests = [], sleeps = [];
|
|
182
|
-
const adapter = createGeminiEmbedder({ apiKey: 'fixture-key', sleep: async ms => sleeps.push(ms), fetchImpl: async (_url, request) => {
|
|
183
|
-
requests.push(JSON.parse(request.body));
|
|
184
|
-
if (requests.length === 1) return new Response('', { status: 503 });
|
|
185
|
-
return Response.json({ embedding: { values: Array(128).fill(0.1) } });
|
|
186
|
-
} });
|
|
187
|
-
const profile = defaultConfig({ dimensions: 128 }).embedding;
|
|
188
|
-
await adapter.embed('function useful() {}', profile);
|
|
189
|
-
await adapter.embed('find useful', profile, { kind: 'query' });
|
|
190
|
-
assert.equal(requests[1].outputDimensionality, 128);
|
|
191
|
-
assert.equal(requests[1].content.parts[0].text, 'title: none | text: function useful() {}');
|
|
192
|
-
assert.equal(requests[2].content.parts[0].text, 'task: code retrieval | query: find useful');
|
|
193
|
-
assert.equal(requests[1].taskType, undefined); assert.equal(sleeps.length, 1);
|
|
194
|
-
await assert.rejects(adapter.embed('x', { ...profile, parameters: { taskType: 'CODE_RETRIEVAL' } }), /Unsupported/);
|
|
195
|
-
let tries = 0;
|
|
196
|
-
const denied = createGeminiEmbedder({ apiKey: 'fixture-key', fetchImpl: async () => { tries++; return new Response('', { status: 403 }); } });
|
|
197
|
-
await assert.rejects(denied.embed('x', profile), /403/); assert.equal(tries, 1);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
test('recovered KnowledgeClient contracts remain usable with injected transports', async () => {
|
|
201
|
-
const operations = [];
|
|
202
|
-
const client = new KnowledgeClient({ transport: { async request(op, payload) { operations.push([op, payload]); return { query_id: 'test', hits: [] }; } } });
|
|
203
|
-
await client.retrieve({ text: 'find parser', workspace_id: 'customer' });
|
|
204
|
-
await client.index('repository');
|
|
205
|
-
assert.equal(operations[0][1].top_k, 8); assert.equal(operations[0][1].token_budget, 6000); assert.equal(operations[0][1].result_policy.max_items, 8); assert.equal(operations[1][0], 'knowledge.index');
|
|
206
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import test from 'node:test';
|
|
3
|
-
import { WebSocket } from 'ws';
|
|
4
|
-
|
|
5
|
-
const liveUrl = String(process.env.AGENTSAM_LIVE_TERMINAL_WS_URL || '').trim();
|
|
6
|
-
|
|
7
|
-
test('live terminal transport accepts a websocket connection', { skip: !liveUrl }, async (t) => {
|
|
8
|
-
const ws = new WebSocket(liveUrl, {
|
|
9
|
-
headers: process.env.AGENTSAM_LIVE_TERMINAL_AUTH
|
|
10
|
-
? { authorization: process.env.AGENTSAM_LIVE_TERMINAL_AUTH }
|
|
11
|
-
: undefined,
|
|
12
|
-
});
|
|
13
|
-
t.after(() => { try { ws.close(); } catch {} });
|
|
14
|
-
|
|
15
|
-
await Promise.race([
|
|
16
|
-
new Promise((resolve, reject) => {
|
|
17
|
-
ws.once('open', resolve);
|
|
18
|
-
ws.once('error', reject);
|
|
19
|
-
}),
|
|
20
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('live terminal websocket open timed out')), 8000)),
|
|
21
|
-
]);
|
|
22
|
-
|
|
23
|
-
assert.equal(ws.readyState, WebSocket.OPEN);
|
|
24
|
-
});
|