Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bff2c42
feat: linkedin
grantdfoster Oct 8, 2025
ee0d463
fix: validation tests
grantdfoster Oct 8, 2025
ed6515a
chore: fix unmarshalling tests
grantdfoster Oct 8, 2025
9bed6c8
chore: adds basic linkedin type tests
grantdfoster Oct 8, 2025
b0e017d
chore: cleanup type tests for linkedin
grantdfoster Oct 8, 2025
5380e85
chore: cleanup errors
grantdfoster Oct 8, 2025
11f7c86
Update args/linkedin/profile/profile.go
grantdfoster Oct 8, 2025
79451b2
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
22d86ea
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
b18850e
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
57f8062
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
7987fef
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
b310fbe
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
0f875ba
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
f4ec5a3
Update types/linkedin/industries/industries.go
grantdfoster Oct 8, 2025
e2dde58
Update types/linkedin/profile/profile.go
grantdfoster Oct 8, 2025
743abdd
chore: fix spacing
grantdfoster Oct 8, 2025
b470b4f
chore: omit empty
grantdfoster Oct 8, 2025
7ded3bd
chore: fix missing omit
grantdfoster Oct 8, 2025
a6a8a58
fix: profile marshalling
grantdfoster Oct 8, 2025
2fca02a
chore: update umarshalling for mode
grantdfoster Oct 8, 2025
d34fe98
chore: update profile
grantdfoster Oct 9, 2025
fa7ca06
chore: fixes test
grantdfoster Oct 9, 2025
117a2ff
fix: max
grantdfoster Oct 9, 2025
6d58128
fix: omitempty
grantdfoster Oct 9, 2025
2f46f90
chore: cleanup
grantdfoster Oct 9, 2025
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
48 changes: 0 additions & 48 deletions .cursor/rules/tee-types_update_plan.mdc

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ go.work
# LLM-related files
.aider*
GEMINI.md

/examples/*json
10 changes: 7 additions & 3 deletions args/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ package args
import (
"encoding/json"
"fmt"
"strings"

"github.com/masa-finance/tee-types/args/linkedin"
teetypes "github.com/masa-finance/tee-types/types"
)

type LinkedInProfileArguments = linkedin.ProfileArguments

// QueryTypeArgument provides a minimal structure to extract the QueryType (json "type")
// This is used across different job types to determine the specific capability being requested
type QueryTypeArgument struct {
QueryType string `json:"type"`
QueryType teetypes.Capability `json:"type"`
}

// UnmarshalJSON implements custom JSON unmarshaling with normalization
Expand All @@ -20,6 +24,6 @@ func (q *QueryTypeArgument) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, aux); err != nil {
return fmt.Errorf("failed to unmarshal QueryType arguments: %w", err)
}
q.QueryType = strings.ToLower(aux.QueryType)
q.QueryType = aux.QueryType
return nil
}
97 changes: 0 additions & 97 deletions args/linkedin.go

This file was deleted.

7 changes: 7 additions & 0 deletions args/linkedin/linkedin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package linkedin

import (
"github.com/masa-finance/tee-types/args/linkedin/profile"
)

type ProfileArguments = profile.Arguments
132 changes: 132 additions & 0 deletions args/linkedin/profile/profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package profile

import (
"encoding/json"
"errors"
"fmt"

teetypes "github.com/masa-finance/tee-types/types"
"github.com/masa-finance/tee-types/types/linkedin/experiences"
"github.com/masa-finance/tee-types/types/linkedin/functions"
"github.com/masa-finance/tee-types/types/linkedin/industries"
"github.com/masa-finance/tee-types/types/linkedin/profile"
"github.com/masa-finance/tee-types/types/linkedin/seniorities"
)

var (
ErrScraperModeNotSupported = errors.New("scraper mode not supported")
ErrMaxItemsTooLarge = errors.New("max items must be less than or equal to 100")
ErrExperienceNotSupported = errors.New("years of experience not supported")
ErrSeniorityNotSupported = errors.New("seniority level not supported")
ErrFunctionNotSupported = errors.New("function not supported")
ErrIndustryNotSupported = errors.New("industry not supported")
)

const (
DefaultMaxItems = 10
DefaultScraperMode = profile.ScraperModeShort
MaxItems = 1000 // 2500 on the actor, but we will run over 1MB memory limit on responses
)

// Arguments defines args for LinkedIn profile operations
type Arguments struct {
QueryType teetypes.Capability `json:"type"`
ScraperMode profile.ScraperMode `json:"profileScraperMode"`
Query string `json:"searchQuery"`
MaxItems uint `json:"maxItems"`
Locations []string `json:"locations,omitempty"`
CurrentCompanies []string `json:"currentCompanies,omitempty"`
PastCompanies []string `json:"pastCompanies,omitempty"`
CurrentJobTitles []string `json:"currentJobTitles,omitempty"`
PastJobTitles []string `json:"pastJobTitles,omitempty"`
Schools []string `json:"schools,omitempty"`
YearsOfExperience []experiences.Id `json:"yearsOfExperienceIds,omitempty"`
YearsAtCurrentCompany []experiences.Id `json:"yearsAtCurrentCompanyIds,omitempty"`
SeniorityLevels []seniorities.Id `json:"seniorityLevelIds,omitempty"`
Functions []functions.Id `json:"functionIds,omitempty"`
Industries []industries.Id `json:"industryIds,omitempty"`
FirstNames []string `json:"firstNames,omitempty"`
LastNames []string `json:"lastNames,omitempty"`
RecentlyChangedJobs bool `json:"recentlyChangedJobs,omitempty"`
StartPage uint `json:"startPage,omitempty"`
}

func (a *Arguments) UnmarshalJSON(data []byte) error {
type Alias Arguments
aux := &struct {
*Alias
}{
Alias: (*Alias)(a),
}

if err := json.Unmarshal(data, aux); err != nil {
return fmt.Errorf("failed to unmarshal LinkedIn profile arguments: %w", err)
}

a.setDefaultValues()

return a.Validate()
}

func (a *Arguments) setDefaultValues() {
if a.MaxItems == 0 {
a.MaxItems = DefaultMaxItems
}
if a.ScraperMode == "" {
a.ScraperMode = DefaultScraperMode
}
}

func (a *Arguments) Validate() error {
var errs []error

if a.MaxItems > MaxItems {
errs = append(errs, ErrMaxItemsTooLarge)
}
if !profile.AllScraperModes.Contains(a.ScraperMode) {
errs = append(errs, ErrScraperModeNotSupported)
}
for _, yoe := range a.YearsOfExperience {
if !experiences.All.Contains(yoe) {
errs = append(errs, fmt.Errorf("%w: %v", ErrExperienceNotSupported, yoe))
}
}
for _, yac := range a.YearsAtCurrentCompany {
if !experiences.All.Contains(yac) {
errs = append(errs, fmt.Errorf("%w: %v", ErrExperienceNotSupported, yac))
}
}
for _, sl := range a.SeniorityLevels {
if !seniorities.All.Contains(sl) {
errs = append(errs, fmt.Errorf("%w: %v", ErrSeniorityNotSupported, sl))
}
}
for _, f := range a.Functions {
if !functions.All.Contains(f) {
errs = append(errs, fmt.Errorf("%w: %v", ErrFunctionNotSupported, f))
}
}
for _, i := range a.Industries {
if !industries.All.Contains(i) {
errs = append(errs, fmt.Errorf("%w: %v", ErrIndustryNotSupported, i))
}
}

if len(errs) > 0 {
return errors.Join(errs...)
}

return nil
}

func (a *Arguments) GetCapability() teetypes.Capability {
return a.QueryType
}

func (a *Arguments) ValidateForJobType(jobType teetypes.JobType) error {
if err := a.Validate(); err != nil {
return err
}

return jobType.ValidateCapability(a.QueryType)
}
13 changes: 13 additions & 0 deletions args/linkedin/profile/profile_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package profile_test

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestArgs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Args Suite")
}
Loading