feat(instrument): Port Agentforce framework adapter (M2)#108
Closed
mmercuri wants to merge 2 commits into
Closed
Conversation
Ports the Salesforce Agentforce framework adapter from ateam (stratix.sdk.python.adapters.agentforce, ~2,954 LOC across 11 files — the largest of the M2 framework batch) onto the layerlens.instrument base layer landed in M1.A. Scope ----- - src/layerlens/instrument/adapters/frameworks/agentforce/ — full port of all 11 modules (adapter, auth, client, events, importer, llm_eval, mapper, models, normalizer, trust_layer, __init__) - src/layerlens/instrument/adapters/frameworks/__init__.py — package marker that does NOT eagerly import any framework SDK - tests/instrument/adapters/frameworks/test_agentforce.py — 36 unit tests (lifecycle, importer with paginated SOQL fixtures, normalizer for every DMO record type, Agent API client/mapper round-trip, Trust Layer YAML emission + deprecation alias, Platform Events handler, Einstein evaluator offline behavior, lazy-import guard). All mocks are SDK-shape only — no real Salesforce / network call. - samples/instrument/agentforce/ — runnable end-to-end sample with 4 mocked flows (SOQL backfill, live Agent API capture, Trust Layer policy export, evaluator offline) plus optional live JWT auth check. - docs/adapters/frameworks-agentforce.md — integration guide including Connected App + JWT Bearer OAuth setup, event taxonomy, capture config, BYOK, Trust Layer round-trip, and replay semantics. - pyproject.toml — new "agentforce" optional extra (requests + PyJWT[crypto]). Salesforce specifics preserved from the source port --------------------------------------------------- - OAuth 2.0 JWT Bearer flow with private-key resolution from env vars, filesystem paths, or inline PEM strings. - SOQL injection guards: every parent ID interpolated into WHERE … IN clauses is validated against the 15/18-char Salesforce ID regex; date and timestamp params validated against ISO 8601 regexes. - Token re-authentication on expiry, with X-RateLimit / Sforce-Limit-Info warnings at 80% consumption. - Trust Layer policy export renamed to_layerlens_policy with a deprecation alias keeping to_stratix_policy callable for one migration window. Verification ------------ - mypy --strict src/layerlens/instrument/adapters/frameworks/agentforce → Success: no issues found in 11 source files - ruff check src/layerlens/instrument/adapters/frameworks/agentforce tests/instrument/adapters/frameworks/test_agentforce.py → All checks passed - pytest tests/instrument/adapters/frameworks/test_agentforce.py → 36 passed - pytest tests/instrument/test_default_install.py → 3 passed (extra does not change default install set) - python samples/instrument/agentforce/main.py → exits 0, prints all 4 flow summaries Refs LAY-INSTRUMENT (M2 fan-out)
Two corrections after running mypy --strict against a fresh resolved environment: - auth.py: drop the now-unused [arg-type] ignore on _check_rate_limit; response.headers from requests already typechecks against the dict[str, Any] parameter. - events.py: include [import-not-found] alongside [import-untyped] in the optional grpc import; mypy resolves grpc to import-not-found when no stubs are installed (the default install path). mypy --strict src/layerlens/instrument/adapters/frameworks/agentforce -> Success: no issues found in 11 source files
7 tasks
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.
Summary
Ports the Salesforce Agentforce framework adapter from
ateam(stratix.sdk.python.adapters.agentforce, ~2,954 LOC across 11 files — the largest of the M2 framework batch) onto thelayerlens.instrumentbase layer landed in M1.A (#93). Self-contained: this PR can be reviewed and merged independent of the other M2 fan-out PRs.Source path:
A:/github/layerlens/ateam/stratix/sdk/python/adapters/agentforce/(adapter,auth,client,events,importer,llm_eval,mapper,models,normalizer,trust_layer,__init__).Template:
langchainframework adapter — same package layout (per-concern modules,ADAPTER_CLASSlazy-loading marker,__all__reexport,requires_pydanticcompat hint).Salesforce Agentforce specifics
This adapter is import-mode rather than runtime monkey-patching: Agentforce is a remote multi-tenant REST service, not a Python library, so there is no in-process SDK to instrument. The adapter:
SalesforceCredentialsaccepts the private key as raw PEM, anenv:NAMEreference, or a filesystem path.AIAgentSession,AIAgentSessionParticipant,AIAgentInteraction,AIAgentInteractionStep,AIAgentInteractionMessage).client.py+mapper.py), Platform Events subscription via gRPC Pub/Sub with CometD long-polling fallback (events.py), Einstein Trust Layer policy round-trip (trust_layer.py), and an LLM evaluator (llm_eval.py).Sforce-Limit-Inforate-limit warnings at 80% consumption.to_stratix_policy(...)is retained as aDeprecationWarningalias forto_layerlens_policy(...)so existingstratix.*callers still work for one migration window.What's in the PR
src/layerlens/instrument/adapters/frameworks/agentforce/(11 files)src/layerlens/instrument/adapters/frameworks/__init__.pytests/instrument/adapters/frameworks/test_agentforce.py(36 tests)samples/instrument/agentforce/main.py+README.mddocs/adapters/frameworks-agentforce.mdpyproject.tomlagentforceextra (requests+PyJWT[crypto])M2 fan-out
This PR is part of the M2 framework adapter fan-out — one self-contained PR per heavy framework (Agentforce is the largest by LOC). It depends on M1.A (#93 — instrument base foundation) but is independent of the other M2 PRs.
Acceptance criteria status
mypy --strict src/layerlens/instrument/adapters/frameworks/agentforce→ Success: no issues found in 11 source filesruff check src/.../agentforce tests/.../test_agentforce.py→ All checks passedpytest tests/instrument/adapters/frameworks/test_agentforce.py→ 36 passedpytest tests/instrument/test_default_install.py→ 3 passed (the newagentforceextra does not perturb the default install set)python samples/instrument/agentforce/main.py→ exit 0, prints all four flow summariesTest plan
mypy --strictclean on the new packageruff checkclean on the new package + testpytest tests/instrument/adapters/frameworks/test_agentforce.pygreen (36 tests)tests/instrument/test_default_install.py) green — confirms theagentforceextra is opt-indocs/adapters/frameworks-agentforce.mdOAuth Connected App section against current Salesforce Setup screensauth.pyJWT signing payload + retry logic for parity with the source portto_stratix_policydeprecation alias matches the rename pattern adopted elsewhere in the M2 batch