failproofai 1.0.7-beta.1 → 1.0.7-beta.2
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +7 -7
- package/.next/standalone/.next/server/app/settings/page.js +2 -2
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l3yhx4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_18qtd42._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0yxwl6j._.js → [root-of-the-server]__0l44ual._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s_yomn._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_214wgrp._.js → _1mel6y1._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_0bn2oo8._.js → _1v-jvrv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_15t8kqj._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1fm2w5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1j0zy3v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +22 -22
- package/.next/standalone/.next/static/chunks/043j99m8ykg__.css +2 -0
- package/.next/standalone/.next/static/chunks/0fqd7m_u81mi5.js +1 -0
- package/.next/standalone/.next/static/chunks/129ag2bw93bdh.js +1 -0
- package/.next/standalone/.next/static/chunks/{29fql3nbnfc9q.js → 1qd741hzlmjbo.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0vmd180qfntfb.js → 2_pltstd8-xgs.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1u5zsejmgrir_.js → 2c8j9l6j_b1ci.js} +1 -1
- package/.next/standalone/.next/static/chunks/3-k569wzcli8q.js +1 -0
- package/.next/standalone/.next/static/chunks/{258668t68du6b.js → 3brze37td_wnc.js} +1 -1
- package/.next/standalone/.next/static/chunks/3otmypm6j_xfo.js +6 -0
- package/.next/standalone/.next/static/chunks/{12tvm75t5ffui.js → 3ugmd_7dyn0id.js} +1 -1
- package/.next/standalone/.next/static/chunks/3yxro_r2_o9ad.js +69 -0
- package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
- package/.next/standalone/app/actions/get-jev-config.ts +38 -23
- package/.next/standalone/app/actions/update-jev-config.ts +1 -1
- package/.next/standalone/app/settings/jev-panel.tsx +33 -29
- package/.next/standalone/package.json +10 -10
- package/.next/standalone/sdk/python/skill/SKILL.md +60 -14
- package/.next/standalone/sdk/python/skill/agents/openai.yaml +2 -1
- package/.next/standalone/sdk/python/skill/references/evaluator.md +255 -0
- package/.next/standalone/sdk/python/skill/references/events.md +17 -8
- package/.next/standalone/sdk/python/skill/references/frameworks.md +3 -0
- package/.next/standalone/sdk/python/skill/references/install.md +3 -0
- package/.next/standalone/sdk/python/skill/references/integration.md +6 -2
- package/.next/standalone/sdk/python/skill/references/typescript.md +568 -0
- package/.next/standalone/sdk/typescript/CHANGELOG.md +119 -0
- package/.next/standalone/sdk/typescript/LICENSE +42 -0
- package/.next/standalone/sdk/typescript/README.md +552 -0
- package/.next/standalone/sdk/typescript/eslint.config.mjs +59 -0
- package/.next/standalone/sdk/typescript/examples/research-agent.ts +197 -0
- package/.next/standalone/sdk/typescript/integration/ai.test.ts +920 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/agent.ts +337 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +281 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/surfaces.ts +605 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/agent.ts +342 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +168 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/surfaces.ts +628 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/agent.ts +346 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +156 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/surfaces.ts +651 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/agent.ts +350 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +153 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/surfaces.ts +651 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/agent.ts +623 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +463 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent-v1.ts +99 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent.ts +623 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +336 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/agent.ts +96 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +579 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.cjs +53 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.mjs +55 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/package.json +18 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/agent.ts +659 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +635 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/agent.ts +659 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +553 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/agent.ts +877 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/mcp-server.mjs +66 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +6417 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/agent.ts +872 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/mcp-server.mjs +66 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +2540 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/actions.ts +18 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/ai/route.ts +42 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/edge/route.ts +29 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/langgraph/route.ts +21 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/llamaindex/route.ts +11 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/mastra/route.ts +19 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/status/route.ts +7 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/layout.tsx +9 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/page.tsx +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/instrumentation.ts +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/ai.ts +61 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/langgraph.ts +68 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/llamaindex.ts +98 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/mastra.ts +90 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/next.config.ts +52 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4343 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +28 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/agent.ts +51 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +76 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +484 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/types/agent.ts +79 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/types/package-lock.json +740 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/types/package.json +11 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/agent.ts +197 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package-lock.json +70 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/global-setup.ts +29 -0
- package/.next/standalone/sdk/typescript/integration/harness.ts +451 -0
- package/.next/standalone/sdk/typescript/integration/langchain.test.ts +682 -0
- package/.next/standalone/sdk/typescript/integration/llamaindex.test.ts +709 -0
- package/.next/standalone/sdk/typescript/integration/mastra-coverage.test.ts +386 -0
- package/.next/standalone/sdk/typescript/integration/mastra.test.ts +311 -0
- package/.next/standalone/sdk/typescript/integration/nextjs.test.ts +341 -0
- package/.next/standalone/sdk/typescript/integration/runtime-parity.ts +180 -0
- package/.next/standalone/sdk/typescript/integration/runtimes.bun.test.ts +15 -0
- package/.next/standalone/sdk/typescript/integration/runtimes.core.test.ts +113 -0
- package/.next/standalone/sdk/typescript/integration/runtimes.deno.test.ts +19 -0
- package/.next/standalone/sdk/typescript/integration/types.test.ts +141 -0
- package/.next/standalone/sdk/typescript/integration/vanilla.test.ts +255 -0
- package/.next/standalone/sdk/typescript/package-lock.json +2640 -0
- package/.next/standalone/sdk/typescript/package.json +401 -0
- package/.next/standalone/sdk/typescript/scripts/finalize-build.mjs +123 -0
- package/.next/standalone/sdk/typescript/scripts/release.mjs +177 -0
- package/.next/standalone/sdk/typescript/src/clock.ts +58 -0
- package/.next/standalone/sdk/typescript/src/context.ts +214 -0
- package/.next/standalone/sdk/typescript/src/edge/adapter.ts +18 -0
- package/.next/standalone/sdk/typescript/src/edge/ai.ts +116 -0
- package/.next/standalone/sdk/typescript/src/edge/index.ts +238 -0
- package/.next/standalone/sdk/typescript/src/edge/langchain.ts +18 -0
- package/.next/standalone/sdk/typescript/src/edge/llamaindex.ts +12 -0
- package/.next/standalone/sdk/typescript/src/edge/mastra.ts +17 -0
- package/.next/standalone/sdk/typescript/src/edge/notice.ts +33 -0
- package/.next/standalone/sdk/typescript/src/environment.ts +75 -0
- package/.next/standalone/sdk/typescript/src/evaluator/authoring.ts +480 -0
- package/.next/standalone/sdk/typescript/src/evaluator/cli.ts +96 -0
- package/.next/standalone/sdk/typescript/src/evaluator/client.ts +421 -0
- package/.next/standalone/sdk/typescript/src/evaluator/expression.ts +1292 -0
- package/.next/standalone/sdk/typescript/src/evaluator/index.ts +144 -0
- package/.next/standalone/sdk/typescript/src/evaluator/protocol.ts +747 -0
- package/.next/standalone/sdk/typescript/src/evaluator/runtime.ts +930 -0
- package/.next/standalone/sdk/typescript/src/evaluator/sandbox-worker.ts +171 -0
- package/.next/standalone/sdk/typescript/src/evaluator/source-limits.ts +27 -0
- package/.next/standalone/sdk/typescript/src/evaluator/source.ts +509 -0
- package/.next/standalone/sdk/typescript/src/events.ts +879 -0
- package/.next/standalone/sdk/typescript/src/exit.ts +117 -0
- package/.next/standalone/sdk/typescript/src/index.ts +186 -0
- package/.next/standalone/sdk/typescript/src/integrations/ai.ts +1566 -0
- package/.next/standalone/sdk/typescript/src/integrations/compat.ts +322 -0
- package/.next/standalone/sdk/typescript/src/integrations/core.ts +1321 -0
- package/.next/standalone/sdk/typescript/src/integrations/index.ts +355 -0
- package/.next/standalone/sdk/typescript/src/integrations/langchain.ts +2340 -0
- package/.next/standalone/sdk/typescript/src/integrations/llamaindex.ts +2111 -0
- package/.next/standalone/sdk/typescript/src/integrations/mastra.ts +1802 -0
- package/.next/standalone/sdk/typescript/src/logger.ts +98 -0
- package/.next/standalone/sdk/typescript/src/next.ts +115 -0
- package/.next/standalone/sdk/typescript/src/node-require.ts +446 -0
- package/.next/standalone/sdk/typescript/src/redact.ts +305 -0
- package/.next/standalone/sdk/typescript/src/resolver.ts +120 -0
- package/.next/standalone/sdk/typescript/src/runtime.ts +29 -0
- package/.next/standalone/sdk/typescript/src/schema.ts +410 -0
- package/.next/standalone/sdk/typescript/src/scopes.ts +701 -0
- package/.next/standalone/sdk/typescript/src/shared.ts +33 -0
- package/.next/standalone/sdk/typescript/src/version.ts +5 -0
- package/.next/standalone/sdk/typescript/src/writer.ts +934 -0
- package/.next/standalone/sdk/typescript/test/adapters.test.ts +397 -0
- package/.next/standalone/sdk/typescript/test/ai.test.ts +1076 -0
- package/.next/standalone/sdk/typescript/test/copies.test.ts +204 -0
- package/.next/standalone/sdk/typescript/test/edge.test.ts +183 -0
- package/.next/standalone/sdk/typescript/test/evaluator-client.test.ts +234 -0
- package/.next/standalone/sdk/typescript/test/evaluator-protocol.test.ts +225 -0
- package/.next/standalone/sdk/typescript/test/events.test.ts +193 -0
- package/.next/standalone/sdk/typescript/test/expression.test.ts +181 -0
- package/.next/standalone/sdk/typescript/test/global-setup.ts +26 -0
- package/.next/standalone/sdk/typescript/test/helpers.ts +130 -0
- package/.next/standalone/sdk/typescript/test/integrations.test.ts +369 -0
- package/.next/standalone/sdk/typescript/test/langchain-copies.test.ts +204 -0
- package/.next/standalone/sdk/typescript/test/langchain.test.ts +999 -0
- package/.next/standalone/sdk/typescript/test/llamaindex.test.ts +1760 -0
- package/.next/standalone/sdk/typescript/test/mastra-coverage.test.ts +501 -0
- package/.next/standalone/sdk/typescript/test/mastra-lifecycle.test.ts +479 -0
- package/.next/standalone/sdk/typescript/test/mastra.test.ts +285 -0
- package/.next/standalone/sdk/typescript/test/next.test.ts +109 -0
- package/.next/standalone/sdk/typescript/test/packaging.test.ts +312 -0
- package/.next/standalone/sdk/typescript/test/redaction.test.ts +171 -0
- package/.next/standalone/sdk/typescript/test/runtimes.test.ts +101 -0
- package/.next/standalone/sdk/typescript/test/sandbox.test.ts +189 -0
- package/.next/standalone/sdk/typescript/test/scopes.test.ts +271 -0
- package/.next/standalone/sdk/typescript/test/setup.ts +19 -0
- package/.next/standalone/sdk/typescript/test/skill-snippets.test.ts +73 -0
- package/.next/standalone/sdk/typescript/test/spool-contract.test.ts +124 -0
- package/.next/standalone/sdk/typescript/test/tracker-bounds.test.ts +191 -0
- package/.next/standalone/sdk/typescript/test/wire-format.test.ts +214 -0
- package/.next/standalone/sdk/typescript/test/writer.test.ts +407 -0
- package/.next/standalone/sdk/typescript/tsconfig.build.json +15 -0
- package/.next/standalone/sdk/typescript/tsconfig.cjs.json +19 -0
- package/.next/standalone/sdk/typescript/tsconfig.json +28 -0
- package/.next/standalone/sdk/typescript/vitest.config.ts +33 -0
- package/.next/standalone/sdk/typescript/vitest.integration.config.ts +23 -0
- package/.next/standalone/server.js +1 -1
- package/README.md +2 -2
- package/dist/cli.mjs +208 -27
- package/dist/worker.mjs +120 -14
- package/package.json +10 -10
- package/scripts/build-policy-pack.mjs +14 -0
- package/src/audit/features.ts +3 -2
- package/src/hooks/builtin-policies.ts +156 -5
- package/src/hooks/jev-cli.ts +57 -1
- package/src/hooks/manager.ts +1 -1
- package/src/hooks/pack-cli.ts +150 -18
- package/src/hooks/pack-store.ts +1 -1
- package/src/hooks/policy-catalog.ts +148 -9
- package/src/hooks/types.ts +1 -1
- package/.next/standalone/.next/static/chunks/0cd-_8-c-m1ea.js +0 -6
- package/.next/standalone/.next/static/chunks/0qrbdkv9qmvli.js +0 -69
- package/.next/standalone/.next/static/chunks/0uldbut9y2-e8.js +0 -1
- package/.next/standalone/.next/static/chunks/285spx855h_3r.css +0 -2
- package/.next/standalone/.next/static/chunks/2vkvu9-opa_1z.js +0 -1
- package/.next/standalone/.next/static/chunks/37lhv7wa3ywt6.js +0 -1
- /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
FORMATS,
|
|
5
|
+
count,
|
|
6
|
+
describeTrace,
|
|
7
|
+
ofType,
|
|
8
|
+
runAgent,
|
|
9
|
+
traceViolations,
|
|
10
|
+
typecheck,
|
|
11
|
+
type Event,
|
|
12
|
+
} from "./harness.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* LangChain.js / LangGraph.js, against real releases.
|
|
16
|
+
*
|
|
17
|
+
* The expected traces are the Python SDK's, captured from its LangChain adapter
|
|
18
|
+
* running the same graph with the same scripted model (langchain-core 1.6.3,
|
|
19
|
+
* langgraph 1.2.11). The two SDKs write into one pipe and the dashboard cannot
|
|
20
|
+
* tell which language wrote what — so for the same program they must draw the
|
|
21
|
+
* same tree. In particular (`sdk/python/skill/references/frameworks.md`):
|
|
22
|
+
*
|
|
23
|
+
* * the root run is the agent, named after the graph;
|
|
24
|
+
* * a LangGraph node is a HOOK (`hook_triggered`/`hook_completed`,
|
|
25
|
+
* `trigger_event="graph_node"`), never a nested agent;
|
|
26
|
+
* * `__start__`, routers, `RunnableSequence` steps and every other piece of
|
|
27
|
+
* machinery emit nothing;
|
|
28
|
+
* * a failure is carried by the events it happened in — no stack of `error`
|
|
29
|
+
* events, one per layer the exception unwound through.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Both ends of the declared peer range (`@langchain/core >=0.3.0 <2`): the 0.3
|
|
34
|
+
* line with LangGraph.js 0.4, and the 1.x line with LangGraph.js 1.x. They
|
|
35
|
+
* differ in exactly the places an adapter breaks on — 0.3 passes no
|
|
36
|
+
* `toolCallId` to `handleToolStart` and LangGraph 0.4 has no graph lifecycle
|
|
37
|
+
* callbacks — so one set of expectations over both is the proof that the
|
|
38
|
+
* adapter covers the range it declares, not just the release it was written on.
|
|
39
|
+
*/
|
|
40
|
+
const FIXTURES = ["langchain-0.3", "langchain-1"] as const;
|
|
41
|
+
|
|
42
|
+
/** One line per event: `agent_id type [hook|tool]`. */
|
|
43
|
+
const shape = (events: Event[]): string[] =>
|
|
44
|
+
events.map((e) =>
|
|
45
|
+
[e.agent_id, e.type, (e.hook_name ?? e.tool_name ?? "") as string].join(" ").trim(),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const GRAPH = [
|
|
49
|
+
"weather_graph agent_start",
|
|
50
|
+
"weather_graph hook_triggered agent",
|
|
51
|
+
"weather_graph model_request",
|
|
52
|
+
"weather_graph model_response",
|
|
53
|
+
"weather_graph hook_completed agent",
|
|
54
|
+
"weather_graph hook_triggered tools",
|
|
55
|
+
"weather_graph tool_use get_weather",
|
|
56
|
+
"weather_graph tool_result get_weather",
|
|
57
|
+
"weather_graph hook_completed tools",
|
|
58
|
+
"weather_graph hook_triggered agent",
|
|
59
|
+
"weather_graph model_request",
|
|
60
|
+
"weather_graph model_response",
|
|
61
|
+
"weather_graph hook_completed agent",
|
|
62
|
+
"weather_graph agent_end",
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The expected trace of each plain-LangChain surface, per session.
|
|
67
|
+
*
|
|
68
|
+
* Captured from the Python adapter running the equivalent program
|
|
69
|
+
* (langchain-core 1.6.3) with `GenericFakeChatModel`; the rule on both sides is
|
|
70
|
+
* the table in `frameworks.md`: the ROOT run is the agent, named by the
|
|
71
|
+
* framework's own run name; an LCEL step, a prompt, a parser, a lambda and a
|
|
72
|
+
* `RunnableParallel` branch emit NOTHING (no `includeChains`); a chat model is
|
|
73
|
+
* its request/response pair; a retriever is a `retriever:<name>` tool pair.
|
|
74
|
+
*
|
|
75
|
+
* Where the agent_id differs from Python's it is the FRAMEWORK's run name that
|
|
76
|
+
* differs, not the mapping:
|
|
77
|
+
* * `RunnableParallel.from({...})` runs as `RunnableMap` in LangChain.js
|
|
78
|
+
* (Python: `RunnableParallel<a,b>`);
|
|
79
|
+
* * a `RunnableLambda` is named `RunnableLambda` whatever its function is
|
|
80
|
+
* called in JS (Python names it after the function), so the case sets the
|
|
81
|
+
* run name to Python's (`shout`) instead;
|
|
82
|
+
* * `withStructuredOutput` names its sequence `StructuredOutput` in JS
|
|
83
|
+
* (Python: `RunnableSequence`).
|
|
84
|
+
* `.batch()` of three inputs is three roots — three sessions, exactly as
|
|
85
|
+
* Python's `.batch()` is.
|
|
86
|
+
*/
|
|
87
|
+
const SURFACES: Record<string, { trace: string[]; sessions?: number }> = {
|
|
88
|
+
lcel: { trace: modelRun("RunnableSequence") },
|
|
89
|
+
sequence: { trace: ["RunnableSequence agent_start", "RunnableSequence agent_end"] },
|
|
90
|
+
parallel: { trace: ["RunnableMap agent_start", "RunnableMap agent_end"] },
|
|
91
|
+
lambda: { trace: ["shout agent_start", "shout agent_end"] },
|
|
92
|
+
retriever: { trace: retrieverRun("Docs", "Docs") },
|
|
93
|
+
vectorstore: { trace: retrieverRun("VectorStoreRetriever", "VectorStoreRetriever") },
|
|
94
|
+
rag: {
|
|
95
|
+
trace: [
|
|
96
|
+
"RunnableSequence agent_start",
|
|
97
|
+
"RunnableSequence tool_use retriever:Docs",
|
|
98
|
+
"RunnableSequence tool_result retriever:Docs",
|
|
99
|
+
"RunnableSequence model_request",
|
|
100
|
+
"RunnableSequence model_response",
|
|
101
|
+
"RunnableSequence agent_end",
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
batch3: { trace: modelRun("RunnableSequence"), sessions: 3 },
|
|
105
|
+
// `streamEvents` v2 attaches LangChain's own event-stream handler beside
|
|
106
|
+
// ours; the trace is the `.invoke()` one, with the stream folded in.
|
|
107
|
+
"stream-events": { trace: modelRun("RunnableSequence") },
|
|
108
|
+
"lcel-stream": { trace: modelRun("RunnableSequence") },
|
|
109
|
+
structured: { trace: modelRun("StructuredOutput") },
|
|
110
|
+
// `bindTools` returns a binding, which is not a run of its own: the model is
|
|
111
|
+
// the root, exactly as Python's `bind_tools(...).invoke()`.
|
|
112
|
+
"bind-tools": { trace: modelRun("ToolCallingModel") },
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
function modelRun(agent: string): string[] {
|
|
116
|
+
return [`${agent} agent_start`, `${agent} model_request`, `${agent} model_response`, `${agent} agent_end`];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function retrieverRun(agent: string, retriever: string): string[] {
|
|
120
|
+
return [
|
|
121
|
+
`${agent} agent_start`,
|
|
122
|
+
`${agent} tool_use retriever:${retriever}`,
|
|
123
|
+
`${agent} tool_result retriever:${retriever}`,
|
|
124
|
+
`${agent} agent_end`,
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The v1 `langchain` package's `createAgent` (langchain 1.5.12), which only the
|
|
130
|
+
* 1.x line has — so it lives in the langchain-1 fixture's own `agent-v1.ts`.
|
|
131
|
+
*
|
|
132
|
+
* Python golden: `langchain.agents.create_agent` 1.4.2 with the same scripted
|
|
133
|
+
* model, `name="weather_agent"`. Identical but for one name: LangChain.js calls
|
|
134
|
+
* the model node `model_request` where Python calls it `model` — the graph's
|
|
135
|
+
* own node name, which both adapters report verbatim.
|
|
136
|
+
*/
|
|
137
|
+
const CREATE_AGENT = [
|
|
138
|
+
"weather_agent agent_start",
|
|
139
|
+
"weather_agent hook_triggered model_request",
|
|
140
|
+
"weather_agent model_request",
|
|
141
|
+
"weather_agent model_response",
|
|
142
|
+
"weather_agent hook_completed model_request",
|
|
143
|
+
"weather_agent hook_triggered tools",
|
|
144
|
+
"weather_agent tool_use get_weather",
|
|
145
|
+
"weather_agent tool_result get_weather",
|
|
146
|
+
"weather_agent hook_completed tools",
|
|
147
|
+
"weather_agent hook_triggered model_request",
|
|
148
|
+
"weather_agent model_request",
|
|
149
|
+
"weather_agent model_response",
|
|
150
|
+
"weather_agent hook_completed model_request",
|
|
151
|
+
"weather_agent agent_end",
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
describe.each(FIXTURES)("%s", (fixture) => {
|
|
155
|
+
it("typechecks as a customer's nodenext ES-module project", () => {
|
|
156
|
+
expect(typecheck(fixture)).toBe("");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe.each(FORMATS)("as %s", (format) => {
|
|
160
|
+
const run = (scenario: string) => {
|
|
161
|
+
const result = runAgent(fixture, format, scenario);
|
|
162
|
+
expect(result.status, describeTrace(result)).toBe(0);
|
|
163
|
+
return result;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
it("records a graph run as one agent with its nodes as hooks", () => {
|
|
167
|
+
const result = run("graph");
|
|
168
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
169
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
170
|
+
expect(new Set(result.events.map((e) => e.session_id)).size).toBe(1);
|
|
171
|
+
for (const hook of ofType(result.events, "hook_triggered")) {
|
|
172
|
+
expect(hook.trigger_event).toBe("graph_node");
|
|
173
|
+
}
|
|
174
|
+
const responses = ofType(result.events, "model_response");
|
|
175
|
+
expect(responses.map((e) => [e.input_tokens, e.output_tokens])).toEqual([
|
|
176
|
+
[12, 5],
|
|
177
|
+
[30, 7],
|
|
178
|
+
]);
|
|
179
|
+
// The model's own tool call id, so a tool_use joins to the tool_calls[]
|
|
180
|
+
// entry that asked for it.
|
|
181
|
+
expect(ofType(result.events, "tool_use")[0]!.tool_call_id).toBe("call_1");
|
|
182
|
+
expect(ofType(result.events, "agent_end")[0]!.outcome).toBe("success");
|
|
183
|
+
for (const event of result.events) {
|
|
184
|
+
expect(event.framework).toBe("langchain");
|
|
185
|
+
expect(typeof event.framework_version).toBe("string");
|
|
186
|
+
}
|
|
187
|
+
expect(result.stdout).toContain("It is sunny in Paris.");
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("records .stream() exactly like .invoke()", () => {
|
|
191
|
+
const result = run("stream");
|
|
192
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("records a prebuilt ReAct agent under its own name", () => {
|
|
196
|
+
const result = run("react");
|
|
197
|
+
expect(shape(result.events), describeTrace(result)).toEqual(
|
|
198
|
+
GRAPH.map((line) => line.replace("weather_graph", "react_bot")),
|
|
199
|
+
);
|
|
200
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("records a failure once, where it happened", () => {
|
|
204
|
+
const result = run("error");
|
|
205
|
+
expect(result.stdout).toContain("model exploded");
|
|
206
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
207
|
+
"weather_graph agent_start",
|
|
208
|
+
"weather_graph hook_triggered agent",
|
|
209
|
+
"weather_graph model_request",
|
|
210
|
+
"weather_graph model_response",
|
|
211
|
+
"weather_graph hook_completed agent",
|
|
212
|
+
"weather_graph agent_end",
|
|
213
|
+
]);
|
|
214
|
+
expect(ofType(result.events, "model_response")[0]!.error).toMatch(/model exploded/);
|
|
215
|
+
expect(ofType(result.events, "hook_completed")[0]!.outcome).toBe("failed");
|
|
216
|
+
expect(ofType(result.events, "agent_end")[0]!.outcome).toBe("failed");
|
|
217
|
+
expect(count(result.events, "error")).toBe(0);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("records a bare model call as its own run", () => {
|
|
221
|
+
const result = run("model");
|
|
222
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
223
|
+
"ScriptedModel agent_start",
|
|
224
|
+
"ScriptedModel model_request",
|
|
225
|
+
"ScriptedModel model_response",
|
|
226
|
+
"ScriptedModel agent_end",
|
|
227
|
+
]);
|
|
228
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("records a bare tool call as its own run", () => {
|
|
232
|
+
const result = run("tool");
|
|
233
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
234
|
+
"get_weather agent_start",
|
|
235
|
+
"get_weather tool_use get_weather",
|
|
236
|
+
"get_weather tool_result get_weather",
|
|
237
|
+
"get_weather agent_end",
|
|
238
|
+
]);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("nests the graph under an enclosing agent() scope", () => {
|
|
242
|
+
const result = run("scope");
|
|
243
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
244
|
+
"planner agent_start",
|
|
245
|
+
...GRAPH,
|
|
246
|
+
"planner agent_end",
|
|
247
|
+
]);
|
|
248
|
+
expect(new Set(result.events.map((e) => e.session_id))).toEqual(new Set(["req-1"]));
|
|
249
|
+
expect(ofType(result.events, "agent_start")[1]!.parent_id).toBe("planner");
|
|
250
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("records through an explicit langchainHandler() without instrument()", () => {
|
|
254
|
+
const result = run("handler");
|
|
255
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("does not double-record when the handler and instrument() are both active", () => {
|
|
259
|
+
const result = run("handler-and-instrument");
|
|
260
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("records nothing after uninstrument()", () => {
|
|
264
|
+
const result = run("uninstrument");
|
|
265
|
+
expect(result.events, describeTrace(result)).toEqual([]);
|
|
266
|
+
expect(result.stdout).toContain('"removed":["langchain"]');
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("records a tool that failed on its tool_result, and the run carries on", () => {
|
|
270
|
+
const result = run("tool-error");
|
|
271
|
+
// `ToolNode` turns the throw into an error ToolMessage, so the graph goes
|
|
272
|
+
// on to answer: the same shape as a clean run, with the failure on the
|
|
273
|
+
// tool span and nowhere else.
|
|
274
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
275
|
+
expect(ofType(result.events, "tool_result")[0]!.error).toBe("Error: no weather for Paris");
|
|
276
|
+
expect(ofType(result.events, "tool_use")[0]!.tool_call_id).toBe("call_1");
|
|
277
|
+
expect(ofType(result.events, "agent_end")[0]!.outcome).toBe("success");
|
|
278
|
+
expect(count(result.events, "error")).toBe(0);
|
|
279
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("records an interrupt() and its Command resume as one paused agent", () => {
|
|
283
|
+
const result = run("hitl");
|
|
284
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
285
|
+
"hitl_graph agent_start",
|
|
286
|
+
"hitl_graph hook_triggered plan",
|
|
287
|
+
"hitl_graph hook_completed plan",
|
|
288
|
+
"hitl_graph hook_triggered approve",
|
|
289
|
+
// The node did not fail, it stopped to ask a human.
|
|
290
|
+
"hitl_graph hook_completed approve",
|
|
291
|
+
"hitl_graph human_wait",
|
|
292
|
+
"hitl_graph agent_pause",
|
|
293
|
+
// The second `.invoke()` is the SAME agent: no second agent_start.
|
|
294
|
+
"hitl_graph agent_resume",
|
|
295
|
+
"hitl_graph human_input",
|
|
296
|
+
"hitl_graph hook_triggered approve",
|
|
297
|
+
"hitl_graph hook_completed approve",
|
|
298
|
+
"hitl_graph hook_triggered act",
|
|
299
|
+
"hitl_graph hook_completed act",
|
|
300
|
+
"hitl_graph agent_end",
|
|
301
|
+
]);
|
|
302
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
303
|
+
expect(new Set(result.events.map((e) => e.session_id))).toEqual(new Set(["t-1"]));
|
|
304
|
+
expect(ofType(result.events, "hook_completed")[1]!.outcome).toBe("paused");
|
|
305
|
+
const wait = ofType(result.events, "human_wait")[0]!;
|
|
306
|
+
expect(wait.prompt).toBe("ship it?");
|
|
307
|
+
expect(wait.options).toEqual(["yes", "no"]);
|
|
308
|
+
expect(wait.reason).toBe("langgraph_interrupt");
|
|
309
|
+
const pauseId = wait.input_id;
|
|
310
|
+
expect(typeof pauseId).toBe("string");
|
|
311
|
+
expect(ofType(result.events, "agent_pause")[0]!.pause_id).toBe(pauseId);
|
|
312
|
+
expect(ofType(result.events, "agent_resume")[0]!.pause_id).toBe(pauseId);
|
|
313
|
+
const answer = ofType(result.events, "human_input")[0]!;
|
|
314
|
+
expect(answer.input_id).toBe(pauseId);
|
|
315
|
+
expect(answer.response).toBe("yes");
|
|
316
|
+
// Control flow, not failure: nothing red anywhere.
|
|
317
|
+
expect(count(result.events, "error")).toBe(0);
|
|
318
|
+
expect(ofType(result.events, "agent_end")[0]!.outcome).toBe("success");
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("closes a paused agent as cancelled at uninstrument()", () => {
|
|
322
|
+
const result = run("hitl-uninstrument");
|
|
323
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
324
|
+
"hitl_graph agent_start",
|
|
325
|
+
"hitl_graph hook_triggered plan",
|
|
326
|
+
"hitl_graph hook_completed plan",
|
|
327
|
+
"hitl_graph hook_triggered approve",
|
|
328
|
+
"hitl_graph hook_completed approve",
|
|
329
|
+
"hitl_graph human_wait",
|
|
330
|
+
"hitl_graph agent_pause",
|
|
331
|
+
"hitl_graph agent_end",
|
|
332
|
+
]);
|
|
333
|
+
expect(ofType(result.events, "agent_end")[0]!.outcome).toBe("cancelled");
|
|
334
|
+
expect(result.stdout).toContain('"removed":["langchain"]');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it("closes a pause opened by another process when this one takes the answer", () => {
|
|
338
|
+
// Process A interrupts and exits; process B shares only the checkpointer.
|
|
339
|
+
// B has no memory of the pause, so the id is rebuilt from the interrupted
|
|
340
|
+
// task's checkpoint namespace — the same derivation `interrupt()` used.
|
|
341
|
+
const result = run("remote-resume");
|
|
342
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
343
|
+
"hitl_graph agent_start",
|
|
344
|
+
"hitl_graph hook_triggered plan",
|
|
345
|
+
"hitl_graph hook_completed plan",
|
|
346
|
+
"hitl_graph hook_triggered approve",
|
|
347
|
+
"hitl_graph hook_completed approve",
|
|
348
|
+
"hitl_graph human_wait",
|
|
349
|
+
"hitl_graph agent_pause",
|
|
350
|
+
// Process B: its own root, then the pause closed where the answered
|
|
351
|
+
// node finished.
|
|
352
|
+
"hitl_graph agent_start",
|
|
353
|
+
"hitl_graph hook_triggered approve",
|
|
354
|
+
"hitl_graph hook_completed approve",
|
|
355
|
+
"hitl_graph agent_resume",
|
|
356
|
+
"hitl_graph human_input",
|
|
357
|
+
"hitl_graph hook_triggered act",
|
|
358
|
+
"hitl_graph hook_completed act",
|
|
359
|
+
"hitl_graph agent_end",
|
|
360
|
+
]);
|
|
361
|
+
const opened = ofType(result.events, "human_wait")[0]!.input_id;
|
|
362
|
+
expect(ofType(result.events, "agent_resume")[0]!.pause_id).toBe(opened);
|
|
363
|
+
const answer = ofType(result.events, "human_input")[0]!;
|
|
364
|
+
expect(answer.input_id).toBe(opened);
|
|
365
|
+
expect(answer.response).toBe("yes");
|
|
366
|
+
expect(answer.fw_resumed_elsewhere).toBe(true);
|
|
367
|
+
expect(new Set(result.events.map((e) => e.session_id))).toEqual(new Set(["t-1"]));
|
|
368
|
+
expect(count(result.events, "error")).toBe(0);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("closes an aborted run as cancelled, not failed", () => {
|
|
372
|
+
const result = run("abort");
|
|
373
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
374
|
+
"abort_graph agent_start",
|
|
375
|
+
"abort_graph hook_triggered slow",
|
|
376
|
+
"abort_graph hook_completed slow",
|
|
377
|
+
"abort_graph agent_end",
|
|
378
|
+
]);
|
|
379
|
+
// A caller that gave up is not a crash: nothing red, and the session
|
|
380
|
+
// closed rather than left running forever.
|
|
381
|
+
expect(ofType(result.events, "hook_completed")[0]!.outcome).toBe("cancelled");
|
|
382
|
+
expect(ofType(result.events, "agent_end")[0]!.outcome).toBe("cancelled");
|
|
383
|
+
expect(count(result.events, "error")).toBe(0);
|
|
384
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it("records a compiled subgraph as a nested agent under its host node", () => {
|
|
388
|
+
const result = run("subgraph");
|
|
389
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
390
|
+
"parent_graph agent_start",
|
|
391
|
+
"parent_graph hook_triggered pre",
|
|
392
|
+
"parent_graph hook_completed pre",
|
|
393
|
+
"parent_graph hook_triggered child",
|
|
394
|
+
"parent_graph/child agent_start",
|
|
395
|
+
"parent_graph/child hook_triggered inner",
|
|
396
|
+
"parent_graph/child hook_completed inner",
|
|
397
|
+
"parent_graph/child agent_end",
|
|
398
|
+
"parent_graph hook_completed child",
|
|
399
|
+
"parent_graph agent_end",
|
|
400
|
+
]);
|
|
401
|
+
expect(ofType(result.events, "agent_start")[1]!.parent_id).toBe("parent_graph");
|
|
402
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it("records each input of a .batch() as its own root", () => {
|
|
406
|
+
const result = run("batch");
|
|
407
|
+
const sessions = [...new Set(result.events.map((e) => e.session_id))];
|
|
408
|
+
expect(sessions).toHaveLength(2);
|
|
409
|
+
for (const session of sessions) {
|
|
410
|
+
expect(shape(result.events.filter((e) => e.session_id === session))).toEqual([
|
|
411
|
+
"ScriptedModel agent_start",
|
|
412
|
+
"ScriptedModel model_request",
|
|
413
|
+
"ScriptedModel model_response",
|
|
414
|
+
"ScriptedModel agent_end",
|
|
415
|
+
]);
|
|
416
|
+
}
|
|
417
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it("folds a streamed model call into one model_response", () => {
|
|
421
|
+
const result = run("stream-model");
|
|
422
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
423
|
+
"StreamingModel agent_start",
|
|
424
|
+
"StreamingModel model_request",
|
|
425
|
+
"StreamingModel model_response",
|
|
426
|
+
"StreamingModel agent_end",
|
|
427
|
+
]);
|
|
428
|
+
const response = ofType(result.events, "model_response")[0]!;
|
|
429
|
+
expect(response.fw_streamed).toBe(true);
|
|
430
|
+
expect(response.fw_chunks).toBe(5);
|
|
431
|
+
expect(typeof response.fw_ttft_ms).toBe("number");
|
|
432
|
+
expect(response.content).toBe("hello there friend");
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("records an intermediate chain only when includeChains names it", () => {
|
|
436
|
+
const result = run("include-chains");
|
|
437
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
438
|
+
"pipeline agent_start",
|
|
439
|
+
"pipeline hook_triggered summarise",
|
|
440
|
+
"pipeline hook_completed summarise",
|
|
441
|
+
"pipeline agent_end",
|
|
442
|
+
]);
|
|
443
|
+
expect(ofType(result.events, "hook_triggered")[0]!.trigger_event).toBe("pipeline");
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("pins every run to the sessionId option", () => {
|
|
447
|
+
const result = run("session-option");
|
|
448
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
449
|
+
expect(new Set(result.events.map((e) => e.session_id))).toEqual(new Set(["fixed-session"]));
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it("takes the session from the documented metadata key", () => {
|
|
453
|
+
const result = run("metadata-session");
|
|
454
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
455
|
+
expect(new Set(result.events.map((e) => e.session_id))).toEqual(new Set(["meta-sid"]));
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it("falls back to the LangGraph thread_id for the session", () => {
|
|
459
|
+
const result = run("thread-session");
|
|
460
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
461
|
+
expect(new Set(result.events.map((e) => e.session_id))).toEqual(new Set(["thread-9"]));
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it("drops prompts, messages and outputs under captureContent: false", () => {
|
|
465
|
+
const result = run("capture-off");
|
|
466
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
467
|
+
for (const event of result.events) {
|
|
468
|
+
for (const key of ["goal", "input", "output", "messages", "content"]) {
|
|
469
|
+
expect(event[key], `${event.type}.${key}`).toBeUndefined();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
// Structure, durations and token counts survive.
|
|
473
|
+
expect(ofType(result.events, "model_response").map((e) => [e.input_tokens, e.output_tokens])).toEqual([
|
|
474
|
+
[12, 5],
|
|
475
|
+
[30, 7],
|
|
476
|
+
]);
|
|
477
|
+
expect(ofType(result.events, "tool_use")[0]!.tool_call_id).toBe("call_1");
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// -- plain LangChain: every surface, instrumented and by explicit handler --
|
|
481
|
+
|
|
482
|
+
describe.each(["instrument", "handler"] as const)("through %s", (mode) => {
|
|
483
|
+
const runSurface = (surface: string) => run(mode === "handler" ? `handler:${surface}` : surface);
|
|
484
|
+
|
|
485
|
+
it.each(Object.keys(SURFACES))("records %s as one root agent per input", (surface) => {
|
|
486
|
+
const expected = SURFACES[surface]!;
|
|
487
|
+
const result = runSurface(surface);
|
|
488
|
+
const sessions = [...new Set(result.events.map((e) => e.session_id))];
|
|
489
|
+
expect(sessions, describeTrace(result)).toHaveLength(expected.sessions ?? 1);
|
|
490
|
+
for (const session of sessions) {
|
|
491
|
+
expect(shape(result.events.filter((e) => e.session_id === session)), describeTrace(result)).toEqual(
|
|
492
|
+
expected.trace,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
496
|
+
if (mode === "handler") expect(result.stdout).not.toContain("instrumented");
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it("summarises a retriever's documents, never their text", () => {
|
|
500
|
+
for (const surface of ["retriever", "rag"]) {
|
|
501
|
+
const result = runSurface(surface);
|
|
502
|
+
const use = ofType(result.events, "tool_use")[0]!;
|
|
503
|
+
const done = ofType(result.events, "tool_result")[0]!;
|
|
504
|
+
expect(use.tool_call_id, describeTrace(result)).toBe(done.tool_call_id);
|
|
505
|
+
expect(use.input).toEqual({ query: surface === "rag" ? "weather?" : "weather in Paris" });
|
|
506
|
+
expect(done.output).toEqual({ n: 2, sources: ["wx.txt", "wx2.txt"] });
|
|
507
|
+
// Not in the retrieval's own events. (In `rag` the documents DO reach
|
|
508
|
+
// the model_request — the chain put them into the prompt.)
|
|
509
|
+
expect(JSON.stringify([use, done])).not.toContain("Rome is rainy");
|
|
510
|
+
}
|
|
511
|
+
const store = runSurface("vectorstore");
|
|
512
|
+
expect(ofType(store.events, "tool_result")[0]!.output, describeTrace(store)).toEqual({ n: 1, sources: ["wx.txt"] });
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
it("folds a streamed chain's tokens into one model_response, usage included", () => {
|
|
516
|
+
for (const surface of ["lcel-stream", "stream-events"]) {
|
|
517
|
+
const result = runSurface(surface);
|
|
518
|
+
const response = ofType(result.events, "model_response")[0]!;
|
|
519
|
+
expect(response.fw_streamed, describeTrace(result)).toBe(true);
|
|
520
|
+
expect(response.fw_chunks).toBe(5);
|
|
521
|
+
expect(typeof response.fw_ttft_ms).toBe("number");
|
|
522
|
+
expect(response.content).toBe("It is sunny in Paris.");
|
|
523
|
+
// Usage arrives on the LAST chunk only; it survives the aggregation.
|
|
524
|
+
expect([response.input_tokens, response.output_tokens]).toEqual([30, 7]);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it("records the tools a model was bound to, for bindTools and withStructuredOutput", () => {
|
|
529
|
+
const bound = runSurface("bind-tools");
|
|
530
|
+
const request = ofType(bound.events, "model_request")[0]!;
|
|
531
|
+
expect(request.model, describeTrace(bound)).toBe("tool-calling-1");
|
|
532
|
+
expect((request.tools as Array<{ function: { name: string } }>).map((t) => t.function.name)).toEqual([
|
|
533
|
+
"get_weather",
|
|
534
|
+
]);
|
|
535
|
+
expect([ofType(bound.events, "model_response")[0]!.input_tokens]).toEqual([12]);
|
|
536
|
+
const structured = runSurface("structured");
|
|
537
|
+
const asked = ofType(structured.events, "model_request")[0]!;
|
|
538
|
+
expect((asked.tools as Array<{ function: { name: string } }>).map((t) => t.function.name)).toEqual(["Weather"]);
|
|
539
|
+
expect(structured.stdout).toContain('{"out":{"city":"Paris","sky":"sunny"}}');
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
describe("langchain-1: createAgent", () => {
|
|
546
|
+
it("typechecks as a customer's nodenext ES-module project", () => {
|
|
547
|
+
// `tsconfig.json` lists both programs, so this covers agent-v1.ts too.
|
|
548
|
+
expect(typecheck("langchain-1")).toBe("");
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
describe.each(FORMATS)("as %s", (format) => {
|
|
552
|
+
const run = (scenario: string) => {
|
|
553
|
+
const result = runAgent("langchain-1", format, scenario, {}, "agent-v1");
|
|
554
|
+
expect(result.status, describeTrace(result)).toBe(0);
|
|
555
|
+
return result;
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
it.each(["create-agent", "handler:create-agent", "create-agent-stream"])(
|
|
559
|
+
"records %s as one agent with its nodes as hooks",
|
|
560
|
+
(scenario) => {
|
|
561
|
+
const result = run(scenario);
|
|
562
|
+
expect(shape(result.events), describeTrace(result)).toEqual(CREATE_AGENT);
|
|
563
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
564
|
+
expect(new Set(result.events.map((e) => e.session_id)).size).toBe(1);
|
|
565
|
+
for (const hook of ofType(result.events, "hook_triggered")) expect(hook.trigger_event).toBe("graph_node");
|
|
566
|
+
expect(ofType(result.events, "tool_use")[0]!.tool_call_id).toBe("call_1");
|
|
567
|
+
expect(ofType(result.events, "model_response").map((e) => [e.input_tokens, e.output_tokens])).toEqual([
|
|
568
|
+
[12, 5],
|
|
569
|
+
[30, 7],
|
|
570
|
+
]);
|
|
571
|
+
},
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
it("records middleware: a node-shaped hook is a hook, a wrapping hook adds nothing", () => {
|
|
575
|
+
// Python golden (`AgentMiddleware` with `before_model` + `wrap_model_call`):
|
|
576
|
+
// `Audit.before_model` is a node before each model turn; `wrap_model_call`
|
|
577
|
+
// runs INSIDE the model node and emits nothing of its own.
|
|
578
|
+
const result = run("create-agent-mw");
|
|
579
|
+
const before = ["weather_agent hook_triggered Audit.before_model", "weather_agent hook_completed Audit.before_model"];
|
|
580
|
+
expect(shape(result.events), describeTrace(result)).toEqual([
|
|
581
|
+
CREATE_AGENT[0],
|
|
582
|
+
...before,
|
|
583
|
+
...CREATE_AGENT.slice(1, 9),
|
|
584
|
+
...before,
|
|
585
|
+
...CREATE_AGENT.slice(9),
|
|
586
|
+
]);
|
|
587
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
it("renders the model node's Command output as messages, not LangChain's serialization envelope", () => {
|
|
591
|
+
// The model node returns `{ output: [Command] }`; its messages used to be
|
|
592
|
+
// captured as `{lc: 1, type: "constructor", id: [...], kwargs}`.
|
|
593
|
+
const result = run("create-agent");
|
|
594
|
+
const done = ofType(result.events, "hook_completed").find((e) => e.hook_name === "model_request")!;
|
|
595
|
+
const text = JSON.stringify(done.output);
|
|
596
|
+
expect(text, describeTrace(result)).not.toContain('"lc":1');
|
|
597
|
+
expect(text).toContain('"type":"ai"');
|
|
598
|
+
expect(text).toContain('"lg_name":"Command"');
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Two copies of `@langchain/core` in one process: the app's 1.2.12 and 0.3.80
|
|
605
|
+
* nested under a provider that pinned it (see the fixture's `agent.ts`).
|
|
606
|
+
*
|
|
607
|
+
* The nested copy's runs INSIDE an app run were always recorded — the child is
|
|
608
|
+
* handed the parent's manager, handler and all. Its ROOT runs were recorded by
|
|
609
|
+
* nothing under `instrument()` until the adapter learned to find and patch the
|
|
610
|
+
* nested copy too. Python has no equivalent (one interpreter imports one
|
|
611
|
+
* `langchain_core`), so the expectation is the mapping rule itself: identical
|
|
612
|
+
* to the same run through the app's own copy.
|
|
613
|
+
*/
|
|
614
|
+
describe("langchain-dup-core: a provider nested on its own @langchain/core", () => {
|
|
615
|
+
const DUP = "langchain-dup-core";
|
|
616
|
+
|
|
617
|
+
it("typechecks as a customer's nodenext ES-module project", () => {
|
|
618
|
+
expect(typecheck(DUP)).toBe("");
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
const NESTED_ROOTS: Record<string, string[]> = {
|
|
622
|
+
"nested-model": modelRun("ChatWeather"),
|
|
623
|
+
"nested-tool": [
|
|
624
|
+
"get_weather agent_start",
|
|
625
|
+
"get_weather tool_use get_weather",
|
|
626
|
+
"get_weather tool_result get_weather",
|
|
627
|
+
"get_weather agent_end",
|
|
628
|
+
],
|
|
629
|
+
"nested-retriever": retrieverRun("WeatherRetriever", "WeatherRetriever"),
|
|
630
|
+
"nested-runnable": ["forecast agent_start", "forecast agent_end"],
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
describe.each(FORMATS)("as %s", (format) => {
|
|
634
|
+
const run = (scenario: string) => {
|
|
635
|
+
const result = runAgent(DUP, format, scenario);
|
|
636
|
+
expect(result.status, describeTrace(result)).toBe(0);
|
|
637
|
+
return result;
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
it.each(Object.keys(NESTED_ROOTS))("records a root started by the nested copy (%s)", (scenario) => {
|
|
641
|
+
const result = run(scenario);
|
|
642
|
+
expect(shape(result.events), describeTrace(result)).toEqual(NESTED_ROOTS[scenario]);
|
|
643
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
it.each(Object.keys(NESTED_ROOTS))("records it through an explicit handler too (%s)", (scenario) => {
|
|
647
|
+
const result = run(`handler:${scenario}`);
|
|
648
|
+
expect(shape(result.events), describeTrace(result)).toEqual(NESTED_ROOTS[scenario]);
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
it("does not double-record a nested root when the handler and instrument() are both active", () => {
|
|
652
|
+
const result = run("both:nested-model");
|
|
653
|
+
expect(shape(result.events), describeTrace(result)).toEqual(NESTED_ROOTS["nested-model"]);
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it("records nothing through the nested copy after uninstrument()", () => {
|
|
657
|
+
const result = run("uninstrument:nested-model");
|
|
658
|
+
expect(result.events, describeTrace(result)).toEqual([]);
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
it("records the nested copy's model inside the app's chain", () => {
|
|
662
|
+
const result = run("app-chain");
|
|
663
|
+
expect(shape(result.events), describeTrace(result)).toEqual(modelRun("RunnableSequence"));
|
|
664
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
it("records the nested copy's model inside the app's lambda, parented through the shared async context", () => {
|
|
668
|
+
const result = run("app-lambda");
|
|
669
|
+
expect(shape(result.events), describeTrace(result)).toEqual(modelRun("outer"));
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
it("records the nested copy's model inside the app's LangGraph graph", () => {
|
|
673
|
+
const result = run("app-graph");
|
|
674
|
+
expect(shape(result.events), describeTrace(result)).toEqual(GRAPH);
|
|
675
|
+
expect(traceViolations(result.events), describeTrace(result)).toEqual([]);
|
|
676
|
+
expect(ofType(result.events, "model_response").map((e) => [e.input_tokens, e.output_tokens])).toEqual([
|
|
677
|
+
[12, 5],
|
|
678
|
+
[30, 7],
|
|
679
|
+
]);
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
});
|