Repository navigation
feat(skills)!: promote Agent Skills to core - #210
jeffdupont wants to merge 10 commits into
Conversation
Every Agent Skills name is now exported from the launchdarkly_ai_server package root (and so from launchdarkly-ai-python), with the same spelling. launchdarkly_ai_server.experimental.skills is removed; import from launchdarkly_ai_server instead. Nothing else changes. - Root __init__ imports and __all__ gain the 24 skills names. - API reports regenerated; the experimental.skills report is gone. - release-please changelog-sections drop the skills Experimental rows. - READMEs, agents.md, AGENTS.md, core docstrings and error strings no longer point at the experimental module. - Tests import skills names from the root; new tests check the root exports them and the experimental module no longer imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A put or delete with no usable key stays warned and ignored, and delivery keeps going. Drop the "experimental stage" and "revisit before 1.0" wording from agents.md and the pinning test's docstring. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Pushed 4825587, which merges origin/main into this branch with no conflicts. This needs a human reviewer. |
XieX
left a comment
There was a problem hiding this comment.
I reviewed the promotion, and the code move itself looks clean: no references to experimental.skills remain, and the root __all__ matches the old module's 24 names. My inline comments are mostly about the docs and packaging around it.
One thing outside the diff: the title's scope is AIC-3655. release-please shows the scope in bold in the changelog entry, so the Jira key would appear in the customer-facing changelog. feat(skills)!: promote Agent Skills to core would land under Features in the same way.
all_skills, get_skill, get_skill_result, get_skills, skill_refs, watch_skills and write_skills each report their client.* usage ID as their first statement (TESTING.md §3.27). The watcher's initial and follow-up reconciles call the non-reporting _write_skills. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y/python-ai-sdk into fix-210-usage
…server 1.0.0 launchdarkly-ai-python doesn't pin launchdarkly-ai-server, so upgrading the barrel alone can leave an older server installed, and importing a skills name then raises ImportError. The promotion removed the README warning along with the experimental bullet. This restores it for the root imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- agents.md: a rename of ld.skills.integrity_failure needs a ! commit, which is a minor bump on 0.x and a major after 1.0, not always a major. - Test that lifecycle.py imports no skills module, so the claim in agents.md is checked now that test_lifecycle no longer asserts it through launchdarkly_ai_server.skills. - test_skills' SKILLS_SURFACE docstring points at the root snapshot test that actually catches an addition. - test_skills_fdv2 imports the internal skills_core and skills_fdv2 apart from the public names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
XieX
left a comment
There was a problem hiding this comment.
Approving. All eight comments from the first round are settled: six are fixed, and the shim and lazy-import decisions are backed by §0.5 and AIC-3674. Thanks for the spec links on the keyless-object rule; ai-sdks-monorepo#86 §3.25 reads the way you described.
Before merging, could you also deal with the follow-ups below?
Docs vs. the new usage reporting (4d6b3cb). The code is right per §3.27, but three places still say skills never calls client.track() or reports telemetry. Details are in the inline comments.
PR description. It still says "Usage IDs. None… this PR adds none." It should now list the seven client.* IDs: skillRefs, getSkill, getSkillResult, getSkills, allSkills, writeSkills and watchSkills.
Changelog. The squash commit only carries the promotion title. Since skills calls now send a usage event, a BEGIN_COMMIT_OVERRIDE with a second line such as feat(skills): report helper usage for the Agent Skills functions would give that its own changelog entry.
Merge timing. This approval doesn't change the "Do not merge yet" note. Please hold until the AIC-3655 blockers are cleared, and make sure this ships as the 1.0 release (AIC-3672). The barrel README now says skills need launchdarkly-ai-server 1.0.0, but the open release PR (#206) would cut 0.5.0. If this lands in a 0.5.0 release, that README note and its pip install "launchdarkly-ai-server>=1.0.0" command would point at a version that doesn't exist.
Jira: [AIC-3655](https://launchdarkly.atlassian.net/browse/AIC-3655) > **Do not merge** until the blockers linked on AIC-3655 are fixed. This PR releases together with the Python and Go promotion PRs (links added later). ## What changed - **Agent Skills is core.** All 35 Agent Skills names (functions, stores, watcher, constants, factories and types) are exported from the `@launchdarkly/ai-server` root with the same spelling, and are **removed** from `@launchdarkly/ai-server/experimental`. This is breaking under the 0.x rule, so it bumps the minor version. - `@launchdarkly/ai-node` gets the names from its root through its existing `export *`. Its `/experimental` entry keeps working and still re-exports Evaluations from Code. - Evaluations from Code stays experimental. The `/experimental` entry point stays. - The API reports (`etc/ai-server.api.md`, `etc/ai-server-experimental.api.md`) are regenerated. The skills names are added to `api-surface/ai-server.txt` as `+` (joining) and marked `-` (leaving) in `api-surface/ai-server.experimental.txt`. - The `skills` rows are removed from `changelog-sections` in `release-please-config.json`. AGENTS.md now says `skills` is a core scope. - The shutdown hook is renamed from `experimental Agent Skills` to `Agent Skills`. The no-store error message now points to `@launchdarkly/ai-server`. Core doc comments no longer call Agent Skills experimental. - Tests: the root export snapshot now includes the skills values, the experimental entry exports only the Evaluations values, a new test checks that the API reports list every skills name at the root and none in the experimental report, and the lifecycle test now expects the `Agent Skills` hook after loading the root and no experimental hook. - The integration fixtures import skills from the root and check that `getSkill` is on the root and not on either `/experimental` subpath. - The READMEs and both agents.md files are updated, including the promotion note. - **Usage IDs:** `main` reports no `experimental.*` skills usage IDs, so this PR adds none. When the skills usage-reporting work (AIC-3555) lands in this SDK, it must use `client.*` IDs. ## Migration Change the import path from `'@launchdarkly/ai-server/experimental'` to `'@launchdarkly/ai-server'` (or from `'@launchdarkly/ai-node/experimental'` to `'@launchdarkly/ai-node'`). Nothing else changes: names, signatures and behavior are the same. ## Test plan Run in the worktree after `yarn install`: - [x] `yarn code:check`: exit 0 - [x] `yarn build`: exit 0 - [x] `yarn typecheck`: exit 0 - [x] `yarn test`: exit 0 (client: 1826 passed, 11 skipped) - [x] `yarn test:integration`: exit 0 (36 passed) - [x] `yarn api:surface`: exit 0 - [x] `yarn test:api-surface`, `yarn test:api-breaking`, `yarn lint:pkg`: exit 0 - [x] `yarn workspace @launchdarkly/ai-server api:check`: exit 0 - [ ] `yarn api:check`: exit 1, only because `packages/claude-agents/etc/ai-claude-agents.api.md` is already out of date on `main` (`ClaudeAgentsHostOptions` came in after the report was last generated). This PR doesn't touch that package. 🤖 Generated with [Claude Code](https://claude.com/claude-code) [AIC-3655]: https://launchdarkly.atlassian.net/browse/AIC-3655?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ ## Related PRs Releases together with: - launchdarkly/python-ai-sdk#210 - launchdarkly/go-ai-sdk#14 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > **Agent Skills moves from `@launchdarkly/ai-server/experimental` to the package root** (and the same via `@launchdarkly/ai-node`). All skills APIs—stores, accessors, `writeSkills`/`watchSkills`, types—are removed from the experimental entry point; **Evaluations from Code** remains on `/experimental` only. This is a **breaking** 0.x change: imports must switch from `.../experimental` to the root; names and behavior are unchanged. > > API Extractor reports and `api-surface/*.txt` are updated accordingly; `skills` is dropped from release-please **Experimental** changelog sections and AGENTS.md now treats `skills` as a core scope. Docs call out that loading the **root** now pulls in Node built-ins (`node:fs`, `node:path`, etc.) for skills, which can break non-Node edge runtimes (tracked as AIC-3674). > > Implementation follow-ups: shutdown hook renamed to `Agent Skills`; skills helpers emit **`client.*` `$ld:ai:sdk:usage` IDs**; `watchSkills` uses `writeSkillsInternal` so only the watcher reports usage. Tests, webpack integration fixtures, and re-export assertions are aligned with the new surface. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ecef311. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
skill_refs now reports client.skillRefs through report_usage, so its docstring and agents.md no longer call it free of telemetry. agents.md names the helper usage event as the one client.track() path, so the skills no-track rule does not read as forbidding it. test_requires_no_client_or_store asserted track() was never called on a client that was never installed. It now checks there is no client or store and that the usage event is held for the next init. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#208 added the Claude Agents skills handler while Agent Skills was still experimental, so it imported launchdarkly_ai_server.experimental.skills. This PR removes that module, which broke the handler, its tests and mypy once main was merged in. The handler itself stays in launchdarkly_ai_claude_agents.experimental.skills. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d679fd2. Configure here.
| ProviderHandler, | ||
| ReconcileReport, | ||
| SkillReference, | ||
| report_usage, |
There was a problem hiding this comment.
Skills imports need a newer server
Medium Severity
create_claude_agents_skills_handler now imports ReconcileReport, SkillReference, skill_refs, and write_skills from the launchdarkly_ai_server root, but launchdarkly-ai-claude-agents still depends on launchdarkly-ai-server>=0.4.1, which only exported those names from experimental.skills. Upgrading the handler alone raises ImportError.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d679fd2. Configure here.


Promotes Agent Skills from
launchdarkly_ai_server.experimental.skillsto the package root. Jira: AIC-3655.Migration
Import Agent Skills names from
launchdarkly_ai_serverinstead oflaunchdarkly_ai_server.experimental.skills. Nothing else changes: the names, signatures and behaviour are the same.This is a breaking change (
!), which bumps the minor version while the package is 0.x.What changed
experimental/skills.pyexported are now inlaunchdarkly_ai_server.__all__, same spelling.launchdarkly-ai-pythonre-exports root__all__withimport *, so it gets them with no code change; its existing re-export tests cover it.experimental/skills.pyis deleted.experimental/__init__.pyis only a docstring, so nothing else there referenced it. Evaluations from Code stays inexperimental.evaluations, untouched.make api-report: the skills names appear inlaunchdarkly_ai_server.txt, andlaunchdarkly_ai_server.experimental.skills.txtis deleted.skills→ Experimental rows are removed fromchangelog-sectionsinrelease-please-config.json, sofeat(skills):now lands under Features.launchdarkly-ai-pythonREADME,packages/client/agents.mdandAGENTS.mdno longer call Agent Skills experimental. Code samples import from the root.skills_core.py,skills_watch.py,types.py,types_validation.py,shutdown_hooks.pyandlifecycle.pyno longer name the experimental module. For example, the "no skill store" error now saysset_skill_store(store) from launchdarkly_ai_server.mainreports no skills usage IDs today, so this PR adds none. When skills usage reporting is added, it must useclient.*IDs, notexperimental.*.parse_ai_configstill passesskillsthrough unvalidated, andskill_refsstill validates it.shutdown()still clears the skill store through the internal shutdown hook. The lifecycle module still imports no skills module.Tests
test_skills.py: every skills name is in root__all__and on the root module.launchdarkly_ai_server.experimental.skillsraisesImportError, andlaunchdarkly_ai_server.experimentalhas none of the names.test_public_surface.py: the skills names are added to theROOT_SURFACEsnapshot.test_lifecycle.py: the "core loads no experimental module" check now checksevaluationsandexperimentalonly, since the root now imports the skills modules.conftest.pyimport from the root.Test plan
Run in the PR worktree after
uv sync(exit 0):make lint— exit 0make format-check— exit 0make typecheck— exit 0 (Success: no issues found in 101 source files)make api-report-check— exit 0 (14 API reports are current)uv run pytest -q packages/client packages/ai— 1709 passed, 1 skippedmake test— exit 2: 3282 passed, 18 skipped, 3 failed. The same 3 tests fail on unmodifiedorigin/main(e3afb3f) in the same checkout, and CI onmainis green. None of them involves skills:test_lifecycle.py::TestInitClientSDKKeyPath::test_uses_options_sdk_key_over_env_varand::test_retries_after_a_failed_init_instead_of_replaying_it: they get a stagingstream_uri. My unverified guess is a local.envabove the checkout leaking into the full run. Both pass when run alone.opencode-agents/tests/test_handler.py::TestProcess::test_a_fake_opencode_is_started_spoken_to_and_stopped: on macOS the temp path comes back as/var/...in one place and/private/var/...in another.🤖 Generated with Claude Code
Related PRs
Releases together with:
Note
Overview
Promotes Agent Skills from experimental to core on
launchdarkly-ai-server: all 24 skills APIs now live onlaunchdarkly_ai_server(and flow throughlaunchdarkly-ai-pythonvia re-export).launchdarkly_ai_server.experimental.skillsis removed—callers must switch imports to the package root (feat(skills)!).The public contract is refreshed: API reports move skills entries into
launchdarkly_ai_server.txt,release-pleasedrops theskillsExperimental changelog scope, and docs/README samples use root imports. Skills helpers now emit SDK-widereport_usage("client.*")events (once per helper per client); watcher-driven reconciles call internal_write_skillsso they do not double-countwriteSkills.Downstream packages (e.g. claude-agents) import store/skill APIs from
launchdarkly_ai_serverinstead ofexperimental.skills; the Claude skills handler stays underexperimental. Tests and lifecycle wording are updated so skills modules are core, while Evaluations remains experimental.Reviewed by Cursor Bugbot for commit d679fd2. Bugbot is set up for automated code reviews on this repo. Configure here.