feat(types): shared session contract package — @codespar/types@0.1.0 (milestone 1) - #7
Merged
Merged
Conversation
Adds packages/session-contract/ with package.json, tsconfig.json, and a stub src/index.ts. The package builds cleanly and is auto-discovered by the npm workspace glob (packages/*). The ./testing subpath export is wired with a development condition — implementation follows in subsequent issues. Closes #2
All adapter packages declared @codespar/sdk@0.2.0 as devDependency while the workspace SDK is at 0.2.2. npm was installing the published 0.2.0 from the registry instead of the workspace link, causing typecheck to resolve against stale types. Bumps all adapter devDependencies to 0.2.2 so they resolve to the workspace link and use the current type definitions.
…guard Introduces the @codespar/session-contract package with two interface layers: - SessionBase: runtime-agnostic (id, status, execute, send, sendStream, connections, close) — usable by any MCP-compatible runtime - Session extends SessionBase: codespar-specific additions (proxyExecute, authorize, mcp?) The SDK's own Session type extends the contract's Session with higher-level helpers (tools, findTools, loop) that will migrate to free functions in the next release, preserving backwards compatibility across all 12 adapter packages in the interim. Also adds isCodesparSession(s: SessionBase): s is Session type guard for use in multi-runtime agents that receive a SessionBase and need to access codespar-specific methods. - Add null-guards to @codespar/mcp (mcp is optional on Session) - Fix status literal narrowing in all adapter fakeSession test mocks
Completes the session-contract wiring across the entire SDK: - @codespar/sdk now declares @codespar/session-contract as a runtime dependency and re-exports all contract types via export * so callers keep their existing import paths unchanged - loop(), tools(), and findTools() are promoted from Session interface methods to free functions (packages/core/src/loop.ts and tools.ts) that accept SessionBase, making them usable with any conforming runtime - @codespar/mcp getMcpConfig and getClaudeDesktopConfig now guard against sessions that do not expose an MCP transport endpoint - All 12 adapter packages updated to call tools(session) (the free function) instead of session.tools() - fakeSession mocks across all adapter test packages cleaned up to reflect the narrower Session interface Breaking change: session.mcp is now typed as optional. Any caller that accessed session.mcp.url or session.mcp.headers without a null-guard will get a TypeScript compile error. Add an explicit check (if (!session.mcp)) before accessing the property. Version bumps: @codespar/sdk 0.3.0, @codespar/mcp 0.3.0, all 12 adapter packages 0.3.0.
Adds runContractSuite(baseUrl, apiKey) in the /testing subpath of @codespar/session-contract. The suite registers vitest test cases that validate the full SessionBase behavioral contract against any live backend: streaming event shapes, execute/ToolResult, send/SendResult, connections, and close/status transition. Key design choices: - InvalidBaseUrlError is thrown synchronously before any fetch so misconfigured CI environments fail at registration time, not mid-run - Only https:// URLs and localhost are accepted to prevent API key exfiltration to arbitrary hosts - The suite builds a minimal raw-fetch SessionBase internally so consumers can call runContractSuite with just a base URL and key - afterEach closes the session in a try/finally block so cleanup runs even when an assertion fails contract-managed.test.ts is gated with describeIf on CONTRACT_API_KEY so the managed leg is skipped (exit 0) in environments without backend access. The managed CI step is added to ci.yml in commented-out form. All four backend prerequisites documented in the comments must be confirmed before the step is enabled.
Adds packages/managed-agents-adapter/ — a bridge between the Anthropic Managed Agents SDK (pre-GA stub) and the codespar SessionBase interface. Any caller typed against SessionBase works unchanged regardless of which runtime backs the session. Key design choices and safety properties: Tool name validation (/^[a-zA-Z0-9_-]+$/) runs before any message is constructed so whitespace or newline characters cannot inject instructions into the JSON payload sent to the Managed Agents API. PolicyHook evaluation runs on the original params BEFORE sanitizeParams is applied. Reversing the order would let a caller strip fields (e.g. amount) that the policy uses to enforce fund-transfer caps. execute(), send(), and sendStream() each acquire a mutex (Promise) and reset it to null in a finally block. Without the finally, a single rejected operation permanently blocks the mutex and every subsequent call hangs. DrainTimeoutError JSDoc explicitly states that callers must not auto-retry commerce tools (Pix transfers, NF-e issuance) after this error — the remote operation may have already executed. AgentRuntime is a local stub interface (pre-GA) with a comment marking the import path to switch to at Anthropic Managed Agents SDK GA. Five error classes: InvalidToolNameError, PolicyViolationError, ApprovalRequiredError, ConcurrentOperationError, DrainTimeoutError.
dangazineu
marked this pull request as ready for review
April 21, 2026 05:55
…ce workspace resolution
^0.2.0 caps at <0.3.0 so npm resolved the published 0.2.2 into each adapter's local node_modules instead of using the workspace package. Bumping to ^0.3.0 aligns the peer constraint with the workspace version, so npm hoists the workspace symlink and no per-package registry copy is installed.
This was referenced Apr 21, 2026
…and policy ordering Covers the three behaviours that are otherwise unverifiable at CI time: - Tool name injection guard (valid/invalid names, error carries offending name) - Mutex lifecycle: ConcurrentOperationError while in-flight, mutex released in finally so the next call goes through after any throw (execute, send, sendStream) - Policy evaluation order: policyHook runs on original params before sanitizeParams, and the runtime receives only the sanitized payload - DrainTimeoutError: thrown when the event stream does not yield a tool_result within the configured deadline; error carries the configured timeout value - Happy-path coverage for execute, send, sendStream, connections, and close
- sendStream returns AsyncIterable not AsyncGenerator; access the iterator via [Symbol.asyncIterator]() before calling .next() - StreamEvent.type is a closed union so comparing to a literal outside the union is a type error; replace with an exact array assertion instead
…me guide - packages/session-contract/README.md: documents SessionBase, Session, isCodesparSession, wire types, and runContractSuite usage - packages/managed-agents-adapter/README.md: documents createManagedAgentsSession, PolicyHook, all error classes, and the pre-GA AgentRuntime stub - docs/custom-session-runtime.md: guide for implementing a custom SessionBase runtime — per-method walkthrough, duck-typing for tools(), conformance testing with runContractSuite, narrowing to Session with isCodesparSession - README.md: add session-contract and managed-agents-adapter to packages table; fix loop example to use the loop() free function - packages/core/README.md: replace session.tools/findTools/loop instance method entries with the free function equivalents; add sendStream and proxyExecute
@codespar/types is more idiomatic for a zero-dep TypeScript interface package. The -contract suffix carries enterprise Java connotations that read oddly in the npm ecosystem. The package covers all shared wire types (ToolResult, SendResult, StreamEvent, etc.) — not just session interfaces — so the broader name is accurate. Renames packages/session-contract/ -> packages/types/, updates all imports, package.json references, README links, and regenerates the lock file.
contract-managed.test.ts targeted api.codespar.dev (the enterprise managed backend) by default. A public MIT repo must not reference or depend on private infrastructure — external contributors can't reach it, and an enterprise outage would break the public CI badge. runContractSuite in @codespar/types/testing stays: it's a generic conformance harness useful to anyone building a custom SessionBase runtime. The test that wires it to the managed backend belongs in codespar-enterprise's CI instead.
Private reference cleanup (touched files):
- Remove codespar-enterprise path and api.codespar.dev from session.ts/index.ts
file headers — those files were edited in this PR and should have been cleaned
- Replace api.codespar.dev with a neutral example URL in mcp test fixtures
- Replace api.codespar.dev example in contract-suite.ts JSDoc (ships in npm)
- Clean up api.codespar.dev reference in sdk test file comment
Dependency pinning:
- Pin @codespar/types to "^0.1.0" in @codespar/sdk (was unbounded "*")
Documentation correctness:
- Fix AuthConfig field: redirectUrl → redirectUri; AuthResult: authUrl → authorizeUrl
- Fix runContractSuite endpoint docs: actual wire format is Bearer auth + {servers,user_id}
body, not {apiKey} body; clarify Vitest-only (not Jest)
- Remove LoopStep.server from README examples — field does not exist on the type
- Clarify that tools() duck-typing is an internal mechanism, not a stable extension point
- Add 0.2.x → 0.3.0 migration note to @codespar/sdk README
Test coverage:
- Add tools.test.ts: covers tools() empty fallback, delegation, findTools() name/
description matching, multi-match, no-match, empty-session cases
- Add cross-method ConcurrentOperationError tests: send() while execute() in flight
and execute() while send() in flight
- Add close()-while-in-flight test: verifies mutex drain before status transitions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Extracts shared session types into a standalone zero-dependency package
(@codespar/types@0.1.0) so any runtime — OSS, managed, or custom — can
conform to the same interface without importing the full SDK.
SessionBase is the minimal runtime-agnostic surface (execute, send,
sendStream, connections, close). Session extends it with codespar-managed
capabilities (proxyExecute, authorize, mcp). isCodesparSession() narrows
SessionBase to Session for callers that need the richer API.
tools(), findTools(), and loop() move from session instance methods to free
functions in @codespar/sdk, accepting any SessionBase. This decouples
orchestration logic from the session type and makes it usable across
runtimes. Callers on 0.2.x: see the migration note in packages/core/README.md.
@codespar/managed-agents-adapter@0.1.0 implements SessionBase against the
Anthropic Managed Agents API (pre-GA stub). Key invariants: tool name
injection guard runs before any message is constructed; PolicyHook evaluates
on original params before sanitizeParams; mutex resets in finally so any
throw leaves the session available for the next call.
@codespar/types/testing exports runContractSuite — a Vitest harness that
fires the five SessionBase methods against a live HTTP endpoint. The OSS
engine leg (starting WebhookServer locally and running the suite against it)
is tracked in codespar/codespar#95.
Closes #2, #3, #4, #5, #6.