Skip to content

S23: spec subpath export - #871

Merged
LinuxDevil merged 9 commits into
mainfrom
fb-s23-spec-subpath
Nov 7, 2026
Merged

LinuxDevil merged 9 commits into
mainfrom
fb-s23-spec-subpath

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

What changed

New lousho/spec subpath — a browser-safe entry that re-exports the merged spec surface with no node: imports anywhere in its graph:

  • v1 agentSpecSchema + AgentSpec; v2 agentSpecV2Schema, parseAgentSpecV2, AgentSpecV2 and every section spec type (ToolRef, SkillRef, MemorySpec, GuardrailSpec, HandoffSpec, HookSpec, PermissionRuleSpec, McpServerSpecV2, TriggerSpec, OutputSpecV2, SubagentSpec, InlineAgentSpec, ...)
  • upgradeSpec, secretRefSchema/isSecretRef/SecretRef, toolRefSchema/TOOL_REF_KINDS, memorySpecSchema, skillRefSchema, triggerSpecSchema, outputSpecSchema helpers (jsonSchemaToStandardSchema), agentSpecV2JsonSchema/SPEC_FIELD_DESCRIPTIONS, specToCode, listModels, listGuardrails, listTriggerTypes
  • S20a–S20c surface: specNodeIds, SpecNodeIds, nodeIdExporter, nodeIdIndexOf, isNodeIdExporter, NodeIdIndex
  • S21b/c surface: flowSpecSchema, flowProblems, FlowProblem, AgentFlow

listBuiltinTools is not exported per the ticket's drop rule: its catalog builds the real tool factories, which pull node:net via web_fetch — it stays on the package root (noted in the entry's JSDoc).

Two leaf extractions keep the provider/executor stack out of the bundle (previously agentSpecV2Schema alone reached them):

  • src/execution/approvalTtl.ts — MAX_APPROVAL_TTL_MS/isApprovalTtl/APPROVAL_TTL_RULE, re-exported by execution/permissions.ts (no API change)
  • src/execution/guardrailLists.ts — PII_TYPES/MODERATION_CATEGORIES, consumed by spec/guardrailOptions.ts (internal-only; public surface unchanged)

Wiring: package.json exports/typesVersions, tsup spec/index entry, typedoc.json entry point, root tsconfig.json lousho/spec path, .fallowrc.json entry (type-only re-exports), api/spec.api.md, mechanical dist→src overrides in examples/imports.test.ts and scripts/verify-docs-snippets.ts (src/spec/index.ts is already the v1 barrel).

Studio: importExport.ts drops its deep ../../../../src/spec/schema import for lousho/spec — the only deep src/spec value import in apps/agent-forge.

Extras: merge-conflict markers left in nodeIdExporter.test.ts from the S20b/S20c merges are resolved keeping both tests; dist/spec/* (+~33 KiB) pushed the tarball over the packed budget — pack-smoke.ts comment notes it and the cap moved 5 → 5.5 MiB; JSDoc on the spec section types lowered the typedoc ratchet baseline 1735 → 1724. The diff also contains the two merge commits pulling fb-s20b-guardrail-spans/fb-s20c-handoff-spans into this branch (S20a–c node-id exporter + guardrail/marker spans) — expected extras of the stacked-PR layout.

Tested

  • npx tsc --noEmit, npm run typecheck:tests, npm run lint — clean
  • npm run test:coverage -- --minWorkers=1 --maxWorkers=4 — 490 files / 7283 tests pass, thresholds met
  • New src/spec/v2/index.test.ts — esbuild platform: 'browser' bundle has no node: import in its metafile graph and zero resolve errors; export key list asserted
  • npm run api:check — all 21 reports up to date (api/spec.api.md new; others only lose // (undocumented) markers via the new JSDoc)
  • npm run fallow — clean (0 dead exports/files)
  • npm run docs:ratchet — 1724 < 1735, baseline lowered and committed
  • npm run docs:llms:check, npm run size-check, npm run docs:verify-snippets -- --source-only — pass (stage A resolves lousho/spec)
  • npm run build, npm run build --workspace apps/agent-forge, npm run typecheck --workspace apps/agent-forge, npm test --workspace apps/agent-forge -- --run (968 tests) — pass
  • npm run pack-smoke — all checks pass: 982 entries, ESM and CJS both load all 21 subpaths incl. lousho/spec, strict-libs clean under zod 3 and zod 4

Acceptance criteria

  • import { agentSpecV2Schema, upgradeSpec, specToCode, listTriggerTypes } from 'lousho/spec' works from ESM and CJS (pack-smoke imports every subpath both ways — the package's real name is lousho, so the subpath is lousho/spec)
  • The browser bundle test passes (no node: in the graph)
  • api/spec.api.md exists and npm run api:check passes
  • Studio builds (npm run build --workspace apps/agent-forge) with no deep src/spec value import left
  • npm run docs:verify-snippets -- --source-only passes (stage A now resolves /spec)

Generated with Devin

LinuxDevil and others added 8 commits November 3, 2026 21:41
…ow spans

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Every guardrail check (input, runInParallel input, output, tool) emits a
`guardrail <name>` span: input/output checks nest under the run's
invoke_agent span, tool checks under that call's execute_tool span. The
span carries only ids and the outcome (lousho.guardrail.name, .kind,
.outcome, .parallel for parallel input checks, gen_ai.tool.name for tool
checks) - never the checked text or the trip reason. With no exporter or
no parent span the check runs directly, as before.

Spec-built agents stamp lousho.node.id = guard:<id>: NodeIdIndex gains
guardrailByName (entry id -> guard:<id>; S11 names each compiled
guardrail by its spec entry id) and the exporter maps 'guardrail ' spans
through it. Unknown names (code-built, inherited) stamp nothing.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add an `approval` flow node (ApprovalStepNode in RuntimeStep) so a human
gate can be its own step: the context's approve callback decides a
flow_approval request carrying { message, stepId }, or a durable run
pauses with status 'awaiting-approval' until FlowExecutor.resume()
brings the decision - exactly as a toolCall that needs approval does.

- flowToolGate: requireApproval renamed to exported requireFlowApproval,
  taking { toolName, toolCallId, args, subject }; toolCall error
  messages unchanged via subject "Tool '<name>'".
- FlowExecutor: approval handler + executeApprovalStep; outputVariable
  receives true once approved; refusal fails LOUSHO_FLOW_TOOL_DENIED.
- docs/flows.md: approval node row + Approval steps section.
- Regenerated api/*.api.md and llms-full.txt.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…-s23-spec-subpath

# Conflicts:
#	docs/observability.md
#	llms-full.txt
#	src/spec/v2/nodeIdExporter.test.ts
#	src/spec/v2/nodeIdExporter.ts
Add a browser-safe lousho/spec subpath that re-exports the spec v1/v2
schemas, their spec types and the pure helpers Studio needs (catalogs,
upgradeSpec, agentSpecV2JsonSchema, specToCode, specNodeIds +
nodeIdExporter, flowProblems + flowSpecSchema, triggerSpecSchema +
listTriggerTypes) with no node:* imports anywhere in its graph.
listBuiltinTools is not exported: its catalog builds the real tool
factories, which pull node:net via web_fetch — it stays on the root.

Two leaf extractions keep the provider/executor stack out of the
browser bundle: approvalTtl.ts (approvalTtlMs/ttlMs helpers, re-exported
by execution/permissions.ts) and guardrailLists.ts (PII_TYPES and
MODERATION_CATEGORIES, consumed by spec/guardrailOptions.ts).

Studio's importExport.ts drops its deep ../../../../src/spec/schema
import for lousho/spec. Also: api/spec.api.md, typedoc/tsconfig/
fallow wiring, a packed-size budget bump in pack-smoke (+~33 KiB for
dist/spec/), JSDoc on the spec section types the entry re-exports
(ratchet baseline 1735 -> 1724), and the leftover merge-conflict
markers in nodeIdExporter.test.ts resolved keeping both tests.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@LinuxDevil
LinuxDevil changed the base branch from fb-s21c-flow-key to main November 7, 2026 12:45
# Conflicts:
#	api/executor.api.md
#	api/flows.api.md
#	api/index.api.md
#	api/kv.api.md
#	api/sqlite.api.md
#	api/types.api.md
#	api/utils.api.md
#	api/worker.api.md
#	scripts/pack-smoke.ts
#	src/spec/v2/flow.ts
@LinuxDevil
LinuxDevil merged commit 0e5b55e into main Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant