Skip to content

πŸ¦‹ New version release - #353

Merged
brentrager merged 1 commit into
mainfrom
changeset-release/main
Aug 14, 2026
Merged

πŸ¦‹ New version release#353
brentrager merged 1 commit into
mainfrom
changeset-release/main

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@smooai/smooth-operator-server@1.9.0

Minor Changes

  • aeb275a: .NET server: resolve send_message.skill server-side (Rust PR th-b30a6a: send_message grows an optional skill β€” the engine resolves it, not the clientΒ #338 parity).

    The C# server had the generated SendMessageRequest.Skill field but ignored it β€” the same staging images went through. It now resolves the skill and composes it into the turn, closing the last text-path gap with the Rust reference:

    • Skills β€” IsValidSkillName (ASCII alphanumerics + -/_, ≀128 chars, so .., /, \ and NUL are unrepresentable rather than filtered), StripFrontmatter (drops the discovery-metadata YAML block, leaving only the instructions the model should see; unterminated frontmatter is returned untouched rather than swallowing the file), SkillSection (the ## Skill: <name> framing), and ResolveSectionAsync.
    • ISkillResolver β€” the host seam, injected via the FrameDispatcher constructor (the C# analog of Rust's AppState::with_skill_resolver).
    • DirSkillResolver β€” the working default: <root>/<name>/SKILL.md over the :-separated roots in SMOOTH_SKILLS_DIR, first root wins. The ASP.NET host prefers a DI-registered ISkillResolver and otherwise falls back to DirSkillResolver.FromEnv(), mirroring Rust's install_skill_resolver_from_env. Unset β‡’ no resolver installed, so a multi-tenant deploy never serves host skills by accident.
    • Fail-CLOSED, unlike images: an unresolvable skill returns error { code: "SKILL_NOT_FOUND" } and the turn does not run. A caller that asked for a code-review recipe and silently got a freeform answer has no way to tell. A blank/whitespace skill is treated as absent, matching Rust's trim-then-filter.
    • The resolved body goes to the system prompt, appended last so it is the most salient instruction into the turn β€” the persisted user message stays exactly what the user typed, so skill prose never accumulates in conversation history and gets replayed every later turn.

    Tests: SkillTests ports all five Rust skills.rs unit tests under their Rust names, plus dispatcher-level coverage for fail-closed SKILL_NOT_FOUND, system-prompt-not-user-message placement, blank-skill-as-absent, and unchanged behavior when the field is absent. RecordingChatClient was promoted out of FileTransferTests into a shared TestChatClients.cs so both suites use one double.

    Backward compatible: an absent skill field is byte-for-byte the previous behavior. Source-only β€” the engine stays the published NuGet.

@brentrager
brentrager force-pushed the changeset-release/main branch from b291839 to a62a7a5 Compare August 14, 2026 00:36
@brentrager
brentrager merged commit 6c2c13a into main Aug 14, 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