feat(agent): read people from Context.dev instead of RapidAPI (CMP-86) - #158
Merged
Conversation
Contributor
There was a problem hiding this comment.
1 issue found across 24 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/agent/test/images.spec.ts">
<violation number="1" location="apps/agent/test/images.spec.ts:13">
P3: photoUrl now accepts any https URL, dropping the previous LinkedIn-CDN allowlist that rejected foreign hosts (e.g. `https://evil.example/x.jpg`). The avatar is fetched server-side by mirror() in storePortrait, so this broadens the set of hosts the runtime pulls from. Confine avatar URLs to trusted CDN hosts (licdn / Context's) as the old profilePhotoUrl did, or document why any https host is acceptable.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| expect( | ||
| profilePhotoUrl({ profilePictureUrl: OVERVIEW.profilePictureURL }), | ||
| ).toBe(OVERVIEW.profilePictureURL); | ||
| it("refuses a face served over anything but https", () => { |
Contributor
There was a problem hiding this comment.
P3: photoUrl now accepts any https URL, dropping the previous LinkedIn-CDN allowlist that rejected foreign hosts (e.g. https://evil.example/x.jpg). The avatar is fetched server-side by mirror() in storePortrait, so this broadens the set of hosts the runtime pulls from. Confine avatar URLs to trusted CDN hosts (licdn / Context's) as the old profilePhotoUrl did, or document why any https host is acceptable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/agent/test/images.spec.ts, line 13:
<comment>photoUrl now accepts any https URL, dropping the previous LinkedIn-CDN allowlist that rejected foreign hosts (e.g. `https://evil.example/x.jpg`). The avatar is fetched server-side by mirror() in storePortrait, so this broadens the set of hosts the runtime pulls from. Confine avatar URLs to trusted CDN hosts (licdn / Context's) as the old profilePhotoUrl did, or document why any https host is acceptable.</comment>
<file context>
@@ -1,48 +1,29 @@
- expect(
- profilePhotoUrl({ profilePictureUrl: OVERVIEW.profilePictureURL }),
- ).toBe(OVERVIEW.profilePictureURL);
+ it("refuses a face served over anything but https", () => {
+ expect(photoUrl("http://media.licdn.com/x.jpg")).toBe(null);
+ expect(photoUrl("ftp://media.licdn.com/x.jpg")).toBe(null);
</file context>
One provider now answers what three did. Context returns the profile, the whole work history, the photograph, education and skills in a single call, so get_linkedin_profile and get_contact_work_history stop making two lookups against an unofficial LinkedIn scraper. linkdapi.ts is deleted. lookupCompany, getCompany and linkedinEnabled had no callers. Enrich reports a score. docs/agent.md refuses a vendor score as proof, so the score never leaves people.ts: matchFrom drops a candidate below the floor and returns only the person. A tool result cannot carry the number, so the model cannot read it as confidence. The verdict is still derived here, from the name and the employer we can see. Calls key on the LinkedIn URL alone. Sending the company we already hold would let Context bias the candidate toward that employer, and we would then verify the employer against the clue we supplied. It also means no customer text leaves for this lookup. A profile that lists the address we are identifying is profile.email-match, the strongest primary evidence there is. The verdict reports it and it settles identity on its own. Both tools charge two units. They make the same twenty credit call, so charging one for work history was a hole. A unit is one metered call, not one credit, and docs/agent.md now says so. The photograph arrives on Context's own CDN rather than LinkedIn, which mirror() copies exactly as before. Verified against the live endpoint, not only fixtures: a real profile returns the name, the roles, the source URL that facts.ts requires, and no score.
ripgrim
force-pushed
the
rg/context-people-enrich
branch
from
August 18, 2026 14:55
5e64d92 to
8237f07
Compare
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.
One provider now answers what three did. Context's
people.enrichreturns the profile, the full work history, the photograph, education and skills in a single call, soget_linkedin_profileandget_contact_work_historystop making two lookups against an unofficial LinkedIn scraper.linkdapi.tsis deleted — 290 lines.lookupCompany,getCompanyandlinkedinEnabledhad no callers.The score never leaves
people.tsdocs/agent.mdrefuses a vendor score as proof.matchFromdrops a candidate below the floor and returns only the person, so a tool result cannot carry the number and the model cannot read it as confidence. A test asserts it is absent. The verdict is still derived here, from the name and employer we can see.Calls key on the LinkedIn URL alone
No name, company or email is sent. Passing the company we already hold would let Context bias the candidate toward that employer, and we would then "verify" the employer against the clue we supplied. It also means no customer text leaves for this lookup.
An email match settles identity
A profile that lists the address we are identifying is
profile.email-match— the strongest primary evidence there is. The verdict reportsemailMatchesand it settles identity on its own, without needing employer and name to agree.identity-matching.mdmaps it.Both tools charge two units
They make the same 20-credit call. Charging one for work history was a hole.
docs/agent.mdnow states that a unit is one metered call, not one credit: a brand lookup is 10 credits, an enrich is 20, and both charge 2 because the budget rations calls per contact.Verified against the live endpoint
Not only fixtures. A real profile returned the name, three current roles, the source URL
facts.tsrequires, and no score. Two things only a live call showed:mirror()— no hotlink blocking.sourceUrlresolved to the LinkedIn URL, so the fact-source rule works on real data.RAPIDAPI_KEYis gone from.env.example,README.md,docs/environment.md, bothturbo.jsonfiles,capabilities.ts, telemetry and its allowlist.git grep -i rapidapireturns nothing.Verification
check-types13/13 ·lint0 ·lint:slop0 ·apps/agent326 pass / 0 fail (was 313, +13 new inpeople.spec.ts) ·apps/api348 pass. Pushed with the pre-push hook running, not--no-verify.Known limits
emailMatchesis untested against real data — the profile I tried lists no address.spend(2)is a considered guess, not a measurement.