Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions packages/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -799,9 +799,10 @@ version does not recognise, not that something failed.

> **Beta caveats, worth knowing before you deploy.** Payload signing does not exist on this
> channel yet, so delivery is TLS-only and the content hash establishes self-consistency, not
> origin authenticity. The FDv2 protocol is opt-in per account: without it the endpoints
> return HTTP 403, which the store reports as a fatal error explaining what to do. `ld-relay`
> does not speak the FDv2 endpoints, so relay-only deployments cannot receive skills.
> origin authenticity. The SDK-facing FDv2 endpoints are available to every account. An
> account without Agent Skills access receives no skill content rather than an error status.
> An HTTP 403 is reported as a fatal error explaining what to check. `ld-relay` does not
> speak the FDv2 endpoints, so relay-only deployments cannot receive skills.

**If every skill comes back empty, check `diagnostics.hashless_objects`.** Objects without a
`contentHash` are withheld, so a nonzero count means skills are being withheld, not that the
Expand Down
7 changes: 4 additions & 3 deletions packages/client/src/launchdarkly_ai_server/skills_fdv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -914,9 +914,10 @@ class _StaleRequestStateError(_RecoverableTransportError):
)

_FORBIDDEN_ADVICE = (
"The FDv2 protocol is opt-in per LaunchDarkly account and is served as HTTP "
"403 while it is off. Skill delivery needs it enabled; contact LaunchDarkly "
"support to enable it for your account."
"The SDK-facing FDv2 endpoints are available to every LaunchDarkly account, "

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want ot prompt them that if you don't have access update your sdk?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this message is the right place for "update your SDK". Two reasons:

  • Anyone who sees this message is already running FDv2SkillStore, so they already have an SDK that supports skills. Updating won't make a 403 go away. A 403 on these endpoints means the request itself was refused, either because of the key or because of a proxy in between.
  • An account without Agent Skills access doesn't get a 403. Gonfalon (SkillDeliveryAllowed) leaves the skill payload out, so the store just comes back empty and this message never shows up.

The people who actually need "update your SDK" are those on the legacy launchdarkly-server-sdk-ai. They never run this code, so they won't see the message at all. That pointer fits better in the README or docs, for example "Skills need launchdarkly-ai-server >= 0.3.0; the legacy launchdarkly-server-sdk-ai doesn't deliver skills." Happy to add that line to the README here (and in js-ai-sdk#141) if you want it.

Written by Devin

"so check that the SDK key is the environment's server-side SDK key and that "
"no proxy in between is refusing the request. If neither explains it, "
"contact LaunchDarkly support."
)


Expand Down
4 changes: 2 additions & 2 deletions packages/client/tests/test_skills_fdv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2136,8 +2136,8 @@ def test_a_403_stops_delivery_and_explains_why(
with poll_store(endpoint) as store:
assert wait_until(lambda: store.failed is not None)
assert "403" in store.failed
assert "opt-in" in store.failed
assert any("opt-in" in r.getMessage() for r in caplog.records)
assert "proxy" in store.failed
assert any("proxy" in r.getMessage() for r in caplog.records)

def test_the_give_up_line_points_at_start_not_a_process_restart(
self, endpoint: Any, caplog: Any
Expand Down
Loading