Compare commits

..

14 Commits

Author SHA1 Message Date
Dean Wenstrand
722b2ca2b0 Re-add legacy shot-sim operations alongside GetShotLabVideos
All checks were successful
Tests / Tests (pull_request) Successful in 1m37s
Mobile master's shot-simulation-screen still uses LiveStreamPicker and
RecordedShotPicker (GetLiveStreams / GetRecordedStreams) while ALSO
using the video-first GetShotLabVideos picker — a transitional state.
1a95439 replaced the old operations in-place, so no gql commit carried
the union and mobile master's pointer could not satisfy its own code.
live_streams.gql is restored verbatim; GetRecordedStreams is re-added
in legacy_shotsim.gql so master's recorded_shots.gql (which now holds
GetShotLabVideos) stays untouched. Drop both when the old pickers are
deleted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 22:57:28 -07:00
79f38fa45f Merge pull request 'dean/nested-comment-replies' (#307) from dean/nested-comment-replies into master
Reviewed-on: #307
2026-07-23 03:24:38 +00:00
Dean Wenstrand
16684f0057 Fetch replyToCommentId in comment reply selections
All checks were successful
Tests / Tests (pull_request) Successful in 12s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 20:06:28 -07:00
Dean Wenstrand
6a599d7d2b Add replyToCommentId to CommentGQL
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 19:59:43 -07:00
2886d2f5b8 Merge pull request 'Select stream.id in upload-status operations so the cache stays normalized' (#306) from dean/upload-stream-id-fields into master
Reviewed-on: #306
2026-07-23 02:38:07 +00:00
Dean Wenstrand
8441bb12e9 Select stream.id in upload-status operations so the cache stays normalized
All checks were successful
Tests / Tests (pull_request) Successful in 11s
UploadStreamWithDetails and the editUploadStream response selected
stream fields without id. Apollo cannot normalize an object with no id
selected, so every upload-service poll rewrote VideoGQL.stream as an
anonymous inline object — clobbering the id that feed/detail queries
select. Their cache reads went partial and useQuery silently fell back
to the last network result, rendered as the home feed collapsing to
the first page (and bouncing the viewport) whenever an upload was
polling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 19:27:25 -07:00
17a518429a Merge pull request 'Add Session Coach generation operations' (#303) from loewy/session-coach-agent-deploy into master
Reviewed-on: #303
2026-07-22 19:25:51 +00:00
33eb213cc9 Add Session Coach generation operations
All checks were successful
Tests / Tests (pull_request) Successful in 3m24s
2026-07-22 11:41:33 -07:00
3b66cb3270 Make video frame rate nullable 2026-07-22 02:20:15 -07:00
d67fdd9fee Merge pull request 'Speed up Shot Lab video source queries' (#304) from codex/fix-shot-lab-video-picker into master
Reviewed-on: #304
2026-07-22 01:08:33 +00:00
d787e5e9a2 Speed up Shot Lab video source queries
All checks were successful
Tests / Tests (pull_request) Successful in 39s
2026-07-21 17:39:55 -07:00
1d73b2d67b Merge pull request 'Declare taxonomy filter variables on the makes/runs leaderboards' (#302) from dean/leaderboard-filter-operations into master
Reviewed-on: #302
2026-07-21 16:59:34 +00:00
Dean Wenstrand
aa731b85fc Declare taxonomy filter variables on the makes/runs leaderboards
All checks were successful
Tests / Tests (pull_request) Successful in 18s
The backend leaderboard resolvers gained game_type, table size and pocket
size filters, but GetMakesLeaderboard and GetRunsLeaderboard never declared
them — GraphQL silently drops undeclared variables, so anything the client
passed was ignored and both boards stayed global.

Declare and forward the five filter args on both queries, matching the
names the drill run leaderboard already uses.
2026-07-21 09:30:37 -07:00
644f70c3b0 Merge pull request 'Shot Lab: video-first GetShotLabVideos (replaces GetRecordedStreams/GetLiveStreams)' (#301) from colonelpanic/shot-lab-video-picker into master 2026-07-21 06:47:45 +00:00
10 changed files with 817 additions and 71 deletions

View File

@@ -274,6 +274,7 @@ export type CommentGql = {
id: Scalars["Int"]["output"]; id: Scalars["Int"]["output"];
message: Scalars["String"]["output"]; message: Scalars["String"]["output"];
replies: Array<CommentGql>; replies: Array<CommentGql>;
replyToCommentId?: Maybe<Scalars["Int"]["output"]>;
user: UserGql; user: UserGql;
}; };
@@ -2554,6 +2555,7 @@ export type Mutation = {
reactToVideo: Scalars["Boolean"]["output"]; reactToVideo: Scalars["Boolean"]["output"];
recalculateChallengeEntry: ChallengeEntry; recalculateChallengeEntry: ChallengeEntry;
reportContent: Scalars["Boolean"]["output"]; reportContent: Scalars["Boolean"]["output"];
requestSessionCoachGeneration: SessionCoachGql;
requestVideoExport: VideoExportJobGql; requestVideoExport: VideoExportJobGql;
respondToChallengeInvitation: ChallengeInvitation; respondToChallengeInvitation: ChallengeInvitation;
retireTags: Scalars["Boolean"]["output"]; retireTags: Scalars["Boolean"]["output"];
@@ -2765,6 +2767,10 @@ export type MutationReportContentArgs = {
videoId: Scalars["Int"]["input"]; videoId: Scalars["Int"]["input"];
}; };
export type MutationRequestSessionCoachGenerationArgs = {
videoId: Scalars["Int"]["input"];
};
export type MutationRequestVideoExportArgs = { export type MutationRequestVideoExportArgs = {
input: RequestVideoExportInput; input: RequestVideoExportInput;
}; };
@@ -3600,6 +3606,18 @@ export enum SessionCoachCandidateKindEnum {
UsagePattern = "USAGE_PATTERN", UsagePattern = "USAGE_PATTERN",
} }
export type SessionCoachDecisionGql = {
__typename?: "SessionCoachDecisionGQL";
body?: Maybe<Scalars["String"]["output"]>;
drillId?: Maybe<Scalars["String"]["output"]>;
drillReason?: Maybe<Scalars["String"]["output"]>;
practiceAttemptCount?: Maybe<Scalars["Int"]["output"]>;
practiceTarget?: Maybe<Scalars["String"]["output"]>;
selectedCandidateId?: Maybe<Scalars["ID"]["output"]>;
suggestedAction?: Maybe<Scalars["String"]["output"]>;
title?: Maybe<Scalars["String"]["output"]>;
};
export type SessionCoachEvidenceGql = { export type SessionCoachEvidenceGql = {
__typename?: "SessionCoachEvidenceGQL"; __typename?: "SessionCoachEvidenceGQL";
attemptCount: Scalars["Int"]["output"]; attemptCount: Scalars["Int"]["output"];
@@ -3618,6 +3636,7 @@ export type SessionCoachEvidenceGql = {
export type SessionCoachGql = { export type SessionCoachGql = {
__typename?: "SessionCoachGQL"; __typename?: "SessionCoachGQL";
agentGeneration?: Maybe<SessionCoachGenerationGql>;
analysisVersion: Scalars["String"]["output"]; analysisVersion: Scalars["String"]["output"];
analyzedShotCount: Scalars["Int"]["output"]; analyzedShotCount: Scalars["Int"]["output"];
candidates: Array<SessionCoachCandidateGql>; candidates: Array<SessionCoachCandidateGql>;
@@ -3636,6 +3655,44 @@ export type SessionCoachGql = {
videoId: Scalars["Int"]["output"]; videoId: Scalars["Int"]["output"];
}; };
export type SessionCoachGenerationDiagnosticsGql = {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
abstentionReason?: Maybe<Scalars["String"]["output"]>;
analysisVersion: Scalars["String"]["output"];
attemptCount: Scalars["Int"]["output"];
cachedInputTokens?: Maybe<Scalars["Int"]["output"]>;
enqueueCount: Scalars["Int"]["output"];
failureCode?: Maybe<Scalars["String"]["output"]>;
inputHash: Scalars["String"]["output"];
inputTokens?: Maybe<Scalars["Int"]["output"]>;
lastEnqueuedAt?: Maybe<Scalars["DateTime"]["output"]>;
latencyMs?: Maybe<Scalars["Int"]["output"]>;
maxAttempts: Scalars["Int"]["output"];
modelName: Scalars["String"]["output"];
outputTokens?: Maybe<Scalars["Int"]["output"]>;
promptVersion: Scalars["String"]["output"];
providerKey: Scalars["String"]["output"];
startedAt?: Maybe<Scalars["DateTime"]["output"]>;
updatedAt: Scalars["DateTime"]["output"];
};
export type SessionCoachGenerationGql = {
__typename?: "SessionCoachGenerationGQL";
completedAt?: Maybe<Scalars["DateTime"]["output"]>;
createdAt: Scalars["DateTime"]["output"];
decision?: Maybe<SessionCoachDecisionGql>;
diagnostics?: Maybe<SessionCoachGenerationDiagnosticsGql>;
id: Scalars["ID"]["output"];
state: SessionCoachGenerationStateEnum;
};
export enum SessionCoachGenerationStateEnum {
Failed = "FAILED",
Queued = "QUEUED",
Ready = "READY",
Running = "RUNNING",
}
export enum SessionCoachIneligibilityReasonEnum { export enum SessionCoachIneligibilityReasonEnum {
Multiplayer = "MULTIPLAYER", Multiplayer = "MULTIPLAYER",
} }
@@ -4259,7 +4316,7 @@ export type VideoGql = {
currentProcessing?: Maybe<VideoProcessingGql>; currentProcessing?: Maybe<VideoProcessingGql>;
elapsedTime?: Maybe<Scalars["Float"]["output"]>; elapsedTime?: Maybe<Scalars["Float"]["output"]>;
endTime?: Maybe<Scalars["DateTime"]["output"]>; endTime?: Maybe<Scalars["DateTime"]["output"]>;
framesPerSecond: Scalars["Float"]["output"]; framesPerSecond?: Maybe<Scalars["Float"]["output"]>;
homographyHistory: Array<HomographyInfoGql>; homographyHistory: Array<HomographyInfoGql>;
id: Scalars["Int"]["output"]; id: Scalars["Int"]["output"];
makePercentage: Scalars["Float"]["output"]; makePercentage: Scalars["Float"]["output"];
@@ -4952,6 +5009,7 @@ export type GetFeedQuery = {
__typename?: "CommentGQL"; __typename?: "CommentGQL";
id: number; id: number;
message: string; message: string;
replyToCommentId?: number | null;
user: { user: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -5067,6 +5125,7 @@ export type VideoCardFieldsFragment = {
__typename?: "CommentGQL"; __typename?: "CommentGQL";
id: number; id: number;
message: string; message: string;
replyToCommentId?: number | null;
user: { user: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -5215,6 +5274,7 @@ export type GetVideoFeedQuery = {
__typename?: "CommentGQL"; __typename?: "CommentGQL";
id: number; id: number;
message: string; message: string;
replyToCommentId?: number | null;
user: { user: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -5236,6 +5296,11 @@ export type GetVideoFeedQuery = {
export type GetMakesLeaderboardQueryVariables = Exact<{ export type GetMakesLeaderboardQueryVariables = Exact<{
interval?: InputMaybe<TimeInterval>; interval?: InputMaybe<TimeInterval>;
when?: InputMaybe<Scalars["DateTime"]["input"]>; when?: InputMaybe<Scalars["DateTime"]["input"]>;
gameType?: InputMaybe<Scalars["String"]["input"]>;
tableSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
tableSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
}>; }>;
export type GetMakesLeaderboardQuery = { export type GetMakesLeaderboardQuery = {
@@ -5260,6 +5325,11 @@ export type GetMakesLeaderboardQuery = {
export type GetRunsLeaderboardQueryVariables = Exact<{ export type GetRunsLeaderboardQueryVariables = Exact<{
interval?: InputMaybe<TimeInterval>; interval?: InputMaybe<TimeInterval>;
when?: InputMaybe<Scalars["DateTime"]["input"]>; when?: InputMaybe<Scalars["DateTime"]["input"]>;
gameType?: InputMaybe<Scalars["String"]["input"]>;
tableSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
tableSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
}>; }>;
export type GetRunsLeaderboardQuery = { export type GetRunsLeaderboardQuery = {
@@ -5344,6 +5414,69 @@ export type GetMyDrillRunsQuery = {
}>; }>;
}; };
export type GetRecordedStreamsQueryVariables = Exact<{
limit?: Scalars["Int"]["input"];
}>;
export type GetRecordedStreamsQuery = {
__typename?: "Query";
getFeedVideos: {
__typename?: "VideoHistoryGQL";
videos: Array<{
__typename?: "VideoGQL";
id: number;
name?: string | null;
createdAt?: any | null;
screenshotUri?: string | null;
framesPerSecond?: number | null;
totalShots: number;
owner?: {
__typename?: "UserGQL";
id: number;
username: string;
profileImageUri?: string | null;
} | null;
}>;
};
};
export type GetLiveStreamsQueryVariables = Exact<{
limit?: Scalars["Int"]["input"];
}>;
export type GetLiveStreamsQuery = {
__typename?: "Query";
getFeedVideos: {
__typename?: "VideoHistoryGQL";
videos: Array<{
__typename?: "VideoGQL";
id: number;
name?: string | null;
startTime?: any | null;
createdAt?: any | null;
screenshotUri?: string | null;
elapsedTime?: number | null;
owner?: {
__typename?: "UserGQL";
id: number;
username: string;
profileImageUri?: string | null;
} | null;
stream?: {
__typename?: "UploadStreamGQL";
id: string;
isCompleted: boolean;
lastSegmentUploadedAt?: any | null;
} | null;
}>;
pageInfo: {
__typename?: "PageInfoGQL";
hasNextPage: boolean;
endCursor?: string | null;
};
};
};
export type GetVideoMakePercentageIntervalsQueryVariables = Exact<{ export type GetVideoMakePercentageIntervalsQueryVariables = Exact<{
videoId: Scalars["ID"]["input"]; videoId: Scalars["ID"]["input"];
intervalDuration: Scalars["Int"]["input"]; intervalDuration: Scalars["Int"]["input"];
@@ -6686,6 +6819,7 @@ export type ReactToVideoMutation = {
}; };
export type GetShotLabVideosQueryVariables = Exact<{ export type GetShotLabVideosQueryVariables = Exact<{
userId: Scalars["Int"]["input"];
limit?: Scalars["Int"]["input"]; limit?: Scalars["Int"]["input"];
}>; }>;
@@ -6699,7 +6833,7 @@ export type GetShotLabVideosQuery = {
name?: string | null; name?: string | null;
createdAt?: any | null; createdAt?: any | null;
screenshotUri?: string | null; screenshotUri?: string | null;
framesPerSecond: number; framesPerSecond?: number | null;
totalShots: number; totalShots: number;
owner?: { owner?: {
__typename?: "UserGQL"; __typename?: "UserGQL";
@@ -6736,29 +6870,13 @@ export type GetRecordedStreamShotsQuery = {
__typename?: "SerializedShotPathsGQL"; __typename?: "SerializedShotPathsGQL";
b64EncodedBuffer?: string | null; b64EncodedBuffer?: string | null;
} | null; } | null;
cueObjectFeatures?: {
__typename?: "CueObjectFeaturesGQL";
cueObjectDistance?: number | null;
cueObjectAngle?: number | null;
cueBallSpeed?: number | null;
shotDirection?: ShotDirectionEnum | null;
spinType?: SpinTypeEnum | null;
} | null;
pocketingIntentionFeatures?: { pocketingIntentionFeatures?: {
__typename?: "PocketingIntentionFeaturesGQL"; __typename?: "PocketingIntentionFeaturesGQL";
make?: boolean | null; make?: boolean | null;
targetPocketDistance?: number | null;
targetPocketAngle?: number | null;
targetPocketAngleDirection?: ShotDirectionEnum | null;
marginOfErrorInDegrees?: number | null;
intendedPocketType?: PocketEnum | null;
difficulty?: number | null;
} | null; } | null;
pocketingIntentionInfo?: { pocketingIntentionInfo?: {
__typename?: "PocketingIntentionInfoGQL"; __typename?: "PocketingIntentionInfoGQL";
ballId: number;
pocketId: PocketIdentifier; pocketId: PocketIdentifier;
pathMetadataIndex: number;
} | null; } | null;
}>; }>;
}; };
@@ -6916,6 +7034,94 @@ export type GetSessionCoachQuery = {
rankReason: string; rankReason: string;
}; };
}>; }>;
agentGeneration?: {
__typename?: "SessionCoachGenerationGQL";
id: string;
state: SessionCoachGenerationStateEnum;
createdAt: any;
completedAt?: any | null;
decision?: {
__typename?: "SessionCoachDecisionGQL";
selectedCandidateId?: string | null;
title?: string | null;
body?: string | null;
suggestedAction?: string | null;
drillId?: string | null;
drillReason?: string | null;
practiceAttemptCount?: number | null;
practiceTarget?: string | null;
} | null;
diagnostics?: {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
analysisVersion: string;
promptVersion: string;
providerKey: string;
modelName: string;
inputHash: string;
attemptCount: number;
maxAttempts: number;
enqueueCount: number;
latencyMs?: number | null;
inputTokens?: number | null;
cachedInputTokens?: number | null;
outputTokens?: number | null;
failureCode?: string | null;
updatedAt: any;
startedAt?: any | null;
lastEnqueuedAt?: any | null;
abstentionReason?: string | null;
} | null;
} | null;
};
};
export type RequestSessionCoachGenerationMutationVariables = Exact<{
videoId: Scalars["Int"]["input"];
}>;
export type RequestSessionCoachGenerationMutation = {
__typename?: "Mutation";
requestSessionCoachGeneration: {
__typename?: "SessionCoachGQL";
state: SessionCoachStateEnum;
agentGeneration?: {
__typename?: "SessionCoachGenerationGQL";
id: string;
state: SessionCoachGenerationStateEnum;
createdAt: any;
completedAt?: any | null;
decision?: {
__typename?: "SessionCoachDecisionGQL";
selectedCandidateId?: string | null;
title?: string | null;
body?: string | null;
suggestedAction?: string | null;
drillId?: string | null;
drillReason?: string | null;
practiceAttemptCount?: number | null;
practiceTarget?: string | null;
} | null;
diagnostics?: {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
analysisVersion: string;
promptVersion: string;
providerKey: string;
modelName: string;
inputHash: string;
attemptCount: number;
maxAttempts: number;
enqueueCount: number;
latencyMs?: number | null;
inputTokens?: number | null;
cachedInputTokens?: number | null;
outputTokens?: number | null;
failureCode?: string | null;
updatedAt: any;
startedAt?: any | null;
lastEnqueuedAt?: any | null;
abstentionReason?: string | null;
} | null;
} | null;
}; };
}; };
@@ -6948,6 +7154,45 @@ export type SessionCoachCandidateFieldsFragment = {
}; };
}; };
export type SessionCoachGenerationFieldsFragment = {
__typename?: "SessionCoachGenerationGQL";
id: string;
state: SessionCoachGenerationStateEnum;
createdAt: any;
completedAt?: any | null;
decision?: {
__typename?: "SessionCoachDecisionGQL";
selectedCandidateId?: string | null;
title?: string | null;
body?: string | null;
suggestedAction?: string | null;
drillId?: string | null;
drillReason?: string | null;
practiceAttemptCount?: number | null;
practiceTarget?: string | null;
} | null;
diagnostics?: {
__typename?: "SessionCoachGenerationDiagnosticsGQL";
analysisVersion: string;
promptVersion: string;
providerKey: string;
modelName: string;
inputHash: string;
attemptCount: number;
maxAttempts: number;
enqueueCount: number;
latencyMs?: number | null;
inputTokens?: number | null;
cachedInputTokens?: number | null;
outputTokens?: number | null;
failureCode?: string | null;
updatedAt: any;
startedAt?: any | null;
lastEnqueuedAt?: any | null;
abstentionReason?: string | null;
} | null;
};
export type PlayerSummaryFieldsFragment = { export type PlayerSummaryFieldsFragment = {
__typename?: "PlayerSummaryGQL"; __typename?: "PlayerSummaryGQL";
clusterId: number; clusterId: number;
@@ -8336,6 +8581,7 @@ export type GetVideoSocialDetailsByIdQuery = {
__typename?: "CommentGQL"; __typename?: "CommentGQL";
id: number; id: number;
message: string; message: string;
replyToCommentId?: number | null;
user: { user: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -8443,6 +8689,7 @@ export type GetVideoCardQuery = {
__typename?: "CommentGQL"; __typename?: "CommentGQL";
id: number; id: number;
message: string; message: string;
replyToCommentId?: number | null;
user: { user: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -8464,7 +8711,7 @@ export type GetVideosQuery = {
getVideos: Array<{ getVideos: Array<{
__typename?: "VideoGQL"; __typename?: "VideoGQL";
id: number; id: number;
framesPerSecond: number; framesPerSecond?: number | null;
stream?: { stream?: {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
@@ -8488,7 +8735,7 @@ export type GetVideosQuery = {
export type VideoStreamMetadataFragment = { export type VideoStreamMetadataFragment = {
__typename?: "VideoGQL"; __typename?: "VideoGQL";
id: number; id: number;
framesPerSecond: number; framesPerSecond?: number | null;
stream?: { stream?: {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
@@ -8517,7 +8764,7 @@ export type GetVideoForShotTimeQuery = {
getVideo: { getVideo: {
__typename?: "VideoGQL"; __typename?: "VideoGQL";
id: number; id: number;
framesPerSecond: number; framesPerSecond?: number | null;
stream?: { stream?: {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
@@ -8688,7 +8935,7 @@ export type PlaylistWithSegmentStartTimesFragment = {
export type VideoDurationDataFragment = { export type VideoDurationDataFragment = {
__typename?: "VideoGQL"; __typename?: "VideoGQL";
id: number; id: number;
framesPerSecond: number; framesPerSecond?: number | null;
playlist?: { playlist?: {
__typename?: "HLSPlaylistGQL"; __typename?: "HLSPlaylistGQL";
videoId: number; videoId: number;
@@ -8725,7 +8972,7 @@ export type GetVideoForClipTimesQuery = {
getVideo: { getVideo: {
__typename?: "VideoGQL"; __typename?: "VideoGQL";
id: number; id: number;
framesPerSecond: number; framesPerSecond?: number | null;
playlist?: { playlist?: {
__typename?: "HLSPlaylistGQL"; __typename?: "HLSPlaylistGQL";
videoId: number; videoId: number;
@@ -9020,6 +9267,7 @@ export type GetUploadLinkMutation = {
}; };
stream?: { stream?: {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string;
uploadCompletionCursor: number; uploadCompletionCursor: number;
} | null; } | null;
}; };
@@ -9118,6 +9366,7 @@ export type UploadStreamWithDetailsFragment = {
startTime?: any | null; startTime?: any | null;
stream?: { stream?: {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string;
isCompleted: boolean; isCompleted: boolean;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
uploadCompletionCursor: number; uploadCompletionCursor: number;
@@ -9142,6 +9391,7 @@ export type GetUploadStreamsWithDetailsQuery = {
startTime?: any | null; startTime?: any | null;
stream?: { stream?: {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string;
isCompleted: boolean; isCompleted: boolean;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
uploadCompletionCursor: number; uploadCompletionCursor: number;
@@ -9243,6 +9493,7 @@ export const VideoCardFieldsFragmentDoc = gql`
replies { replies {
id id
message message
replyToCommentId
user { user {
...UserSocialsFields ...UserSocialsFields
} }
@@ -9422,6 +9673,43 @@ export const SessionCoachCandidateFieldsFragmentDoc = gql`
} }
} }
`; `;
export const SessionCoachGenerationFieldsFragmentDoc = gql`
fragment SessionCoachGenerationFields on SessionCoachGenerationGQL {
id
state
createdAt
completedAt
decision {
selectedCandidateId
title
body
suggestedAction
drillId
drillReason
practiceAttemptCount
practiceTarget
}
diagnostics {
analysisVersion
promptVersion
providerKey
modelName
inputHash
attemptCount
maxAttempts
enqueueCount
latencyMs
inputTokens
cachedInputTokens
outputTokens
failureCode
updatedAt
startedAt
lastEnqueuedAt
abstentionReason
}
}
`;
export const PlayerClusterShotFieldsFragmentDoc = gql` export const PlayerClusterShotFieldsFragmentDoc = gql`
fragment PlayerClusterShotFields on PlayerClusterShotGQL { fragment PlayerClusterShotFields on PlayerClusterShotGQL {
shotId shotId
@@ -9681,6 +9969,7 @@ export const UploadStreamWithDetailsFragmentDoc = gql`
name name
startTime startTime
stream { stream {
id
isCompleted isCompleted
lastIntendedSegmentBound lastIntendedSegmentBound
uploadCompletionCursor uploadCompletionCursor
@@ -11754,8 +12043,24 @@ export type GetVideoFeedQueryResult = Apollo.QueryResult<
GetVideoFeedQueryVariables GetVideoFeedQueryVariables
>; >;
export const GetMakesLeaderboardDocument = gql` export const GetMakesLeaderboardDocument = gql`
query GetMakesLeaderboard($interval: TimeInterval, $when: DateTime) { query GetMakesLeaderboard(
getMakesLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getMakesLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
user { user {
id id
@@ -11784,6 +12089,11 @@ export const GetMakesLeaderboardDocument = gql`
* variables: { * variables: {
* interval: // value for 'interval' * interval: // value for 'interval'
* when: // value for 'when' * when: // value for 'when'
* gameType: // value for 'gameType'
* tableSizeMin: // value for 'tableSizeMin'
* tableSizeMax: // value for 'tableSizeMax'
* pocketSizeMin: // value for 'pocketSizeMin'
* pocketSizeMax: // value for 'pocketSizeMax'
* }, * },
* }); * });
*/ */
@@ -11837,8 +12147,24 @@ export type GetMakesLeaderboardQueryResult = Apollo.QueryResult<
GetMakesLeaderboardQueryVariables GetMakesLeaderboardQueryVariables
>; >;
export const GetRunsLeaderboardDocument = gql` export const GetRunsLeaderboardDocument = gql`
query GetRunsLeaderboard($interval: TimeInterval, $when: DateTime) { query GetRunsLeaderboard(
getLongestRunsLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getLongestRunsLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
id id
runLength runLength
@@ -11870,6 +12196,11 @@ export const GetRunsLeaderboardDocument = gql`
* variables: { * variables: {
* interval: // value for 'interval' * interval: // value for 'interval'
* when: // value for 'when' * when: // value for 'when'
* gameType: // value for 'gameType'
* tableSizeMin: // value for 'tableSizeMin'
* tableSizeMax: // value for 'tableSizeMax'
* pocketSizeMin: // value for 'pocketSizeMin'
* pocketSizeMax: // value for 'pocketSizeMax'
* }, * },
* }); * });
*/ */
@@ -12117,6 +12448,195 @@ export type GetMyDrillRunsQueryResult = Apollo.QueryResult<
GetMyDrillRunsQuery, GetMyDrillRunsQuery,
GetMyDrillRunsQueryVariables GetMyDrillRunsQueryVariables
>; >;
export const GetRecordedStreamsDocument = gql`
query GetRecordedStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
createdAt
screenshotUri
framesPerSecond
totalShots
owner {
id
username
profileImageUri
}
}
}
}
`;
/**
* __useGetRecordedStreamsQuery__
*
* To run a query within a React component, call `useGetRecordedStreamsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetRecordedStreamsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetRecordedStreamsQuery({
* variables: {
* limit: // value for 'limit'
* },
* });
*/
export function useGetRecordedStreamsQuery(
baseOptions?: Apollo.QueryHookOptions<
GetRecordedStreamsQuery,
GetRecordedStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<
GetRecordedStreamsQuery,
GetRecordedStreamsQueryVariables
>(GetRecordedStreamsDocument, options);
}
export function useGetRecordedStreamsLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<
GetRecordedStreamsQuery,
GetRecordedStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<
GetRecordedStreamsQuery,
GetRecordedStreamsQueryVariables
>(GetRecordedStreamsDocument, options);
}
export function useGetRecordedStreamsSuspenseQuery(
baseOptions?: Apollo.SuspenseQueryHookOptions<
GetRecordedStreamsQuery,
GetRecordedStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useSuspenseQuery<
GetRecordedStreamsQuery,
GetRecordedStreamsQueryVariables
>(GetRecordedStreamsDocument, options);
}
export type GetRecordedStreamsQueryHookResult = ReturnType<
typeof useGetRecordedStreamsQuery
>;
export type GetRecordedStreamsLazyQueryHookResult = ReturnType<
typeof useGetRecordedStreamsLazyQuery
>;
export type GetRecordedStreamsSuspenseQueryHookResult = ReturnType<
typeof useGetRecordedStreamsSuspenseQuery
>;
export type GetRecordedStreamsQueryResult = Apollo.QueryResult<
GetRecordedStreamsQuery,
GetRecordedStreamsQueryVariables
>;
export const GetLiveStreamsDocument = gql`
query GetLiveStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: false, requireCursorCompletion: false }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
startTime
createdAt
screenshotUri
elapsedTime
owner {
id
username
profileImageUri
}
stream {
id
isCompleted
lastSegmentUploadedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`;
/**
* __useGetLiveStreamsQuery__
*
* To run a query within a React component, call `useGetLiveStreamsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetLiveStreamsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetLiveStreamsQuery({
* variables: {
* limit: // value for 'limit'
* },
* });
*/
export function useGetLiveStreamsQuery(
baseOptions?: Apollo.QueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<GetLiveStreamsQuery, GetLiveStreamsQueryVariables>(
GetLiveStreamsDocument,
options,
);
}
export function useGetLiveStreamsLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<GetLiveStreamsQuery, GetLiveStreamsQueryVariables>(
GetLiveStreamsDocument,
options,
);
}
export function useGetLiveStreamsSuspenseQuery(
baseOptions?: Apollo.SuspenseQueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useSuspenseQuery<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>(GetLiveStreamsDocument, options);
}
export type GetLiveStreamsQueryHookResult = ReturnType<
typeof useGetLiveStreamsQuery
>;
export type GetLiveStreamsLazyQueryHookResult = ReturnType<
typeof useGetLiveStreamsLazyQuery
>;
export type GetLiveStreamsSuspenseQueryHookResult = ReturnType<
typeof useGetLiveStreamsSuspenseQuery
>;
export type GetLiveStreamsQueryResult = Apollo.QueryResult<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>;
export const GetVideoMakePercentageIntervalsDocument = gql` export const GetVideoMakePercentageIntervalsDocument = gql`
query GetVideoMakePercentageIntervals( query GetVideoMakePercentageIntervals(
$videoId: ID! $videoId: ID!
@@ -14416,11 +14936,12 @@ export type ReactToVideoMutationOptions = Apollo.BaseMutationOptions<
ReactToVideoMutationVariables ReactToVideoMutationVariables
>; >;
export const GetShotLabVideosDocument = gql` export const GetShotLabVideosDocument = gql`
query GetShotLabVideos($limit: Int! = 25) { query GetShotLabVideos($userId: Int!, $limit: Int! = 25) {
getFeedVideos( getFeedVideos(
limit: $limit limit: $limit
includeCallersVideos: false
includePrivate: MINE includePrivate: MINE
feedInput: { allUsers: true } feedInput: { userId: $userId }
) { ) {
videos { videos {
id id
@@ -14456,12 +14977,13 @@ export const GetShotLabVideosDocument = gql`
* @example * @example
* const { data, loading, error } = useGetShotLabVideosQuery({ * const { data, loading, error } = useGetShotLabVideosQuery({
* variables: { * variables: {
* userId: // value for 'userId'
* limit: // value for 'limit' * limit: // value for 'limit'
* }, * },
* }); * });
*/ */
export function useGetShotLabVideosQuery( export function useGetShotLabVideosQuery(
baseOptions?: Apollo.QueryHookOptions< baseOptions: Apollo.QueryHookOptions<
GetShotLabVideosQuery, GetShotLabVideosQuery,
GetShotLabVideosQueryVariables GetShotLabVideosQueryVariables
>, >,
@@ -14524,26 +15046,11 @@ export const GetRecordedStreamShotsDocument = gql`
serializedShotPaths { serializedShotPaths {
b64EncodedBuffer b64EncodedBuffer
} }
cueObjectFeatures {
cueObjectDistance
cueObjectAngle
cueBallSpeed
shotDirection
spinType
}
pocketingIntentionFeatures { pocketingIntentionFeatures {
make make
targetPocketDistance
targetPocketAngle
targetPocketAngleDirection
marginOfErrorInDegrees
intendedPocketType
difficulty
} }
pocketingIntentionInfo { pocketingIntentionInfo {
ballId
pocketId pocketId
pathMetadataIndex
} }
} }
} }
@@ -14838,9 +15345,13 @@ export const GetSessionCoachDocument = gql`
candidates { candidates {
...SessionCoachCandidateFields ...SessionCoachCandidateFields
} }
agentGeneration {
...SessionCoachGenerationFields
}
} }
} }
${SessionCoachCandidateFieldsFragmentDoc} ${SessionCoachCandidateFieldsFragmentDoc}
${SessionCoachGenerationFieldsFragmentDoc}
`; `;
/** /**
@@ -14908,6 +15419,61 @@ export type GetSessionCoachQueryResult = Apollo.QueryResult<
GetSessionCoachQuery, GetSessionCoachQuery,
GetSessionCoachQueryVariables GetSessionCoachQueryVariables
>; >;
export const RequestSessionCoachGenerationDocument = gql`
mutation RequestSessionCoachGeneration($videoId: Int!) {
requestSessionCoachGeneration(videoId: $videoId) {
state
agentGeneration {
...SessionCoachGenerationFields
}
}
}
${SessionCoachGenerationFieldsFragmentDoc}
`;
export type RequestSessionCoachGenerationMutationFn = Apollo.MutationFunction<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>;
/**
* __useRequestSessionCoachGenerationMutation__
*
* To run a mutation, you first call `useRequestSessionCoachGenerationMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useRequestSessionCoachGenerationMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [requestSessionCoachGenerationMutation, { data, loading, error }] = useRequestSessionCoachGenerationMutation({
* variables: {
* videoId: // value for 'videoId'
* },
* });
*/
export function useRequestSessionCoachGenerationMutation(
baseOptions?: Apollo.MutationHookOptions<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useMutation<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>(RequestSessionCoachGenerationDocument, options);
}
export type RequestSessionCoachGenerationMutationHookResult = ReturnType<
typeof useRequestSessionCoachGenerationMutation
>;
export type RequestSessionCoachGenerationMutationResult =
Apollo.MutationResult<RequestSessionCoachGenerationMutation>;
export type RequestSessionCoachGenerationMutationOptions =
Apollo.BaseMutationOptions<
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>;
export const VideoPlayerClustersDocument = gql` export const VideoPlayerClustersDocument = gql`
query VideoPlayerClusters($videoId: Int!) { query VideoPlayerClusters($videoId: Int!) {
videoPlayerClusters(videoId: $videoId) { videoPlayerClusters(videoId: $videoId) {
@@ -18062,6 +18628,7 @@ export const GetVideoSocialDetailsByIdDocument = gql`
replies { replies {
id id
message message
replyToCommentId
user { user {
...UserSocialsFields ...UserSocialsFields
} }
@@ -19369,6 +19936,7 @@ export const GetUploadLinkDocument = gql`
} }
} }
stream { stream {
id
uploadCompletionCursor uploadCompletionCursor
} }
} }

View File

@@ -78,6 +78,7 @@ fragment VideoCardFields on VideoGQL {
replies { replies {
id id
message message
replyToCommentId
user { user {
...UserSocialsFields ...UserSocialsFields
} }

View File

@@ -1,5 +1,21 @@
query GetMakesLeaderboard($interval: TimeInterval, $when: DateTime) { query GetMakesLeaderboard(
getMakesLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getMakesLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
user { user {
id id
@@ -13,8 +29,24 @@ query GetMakesLeaderboard($interval: TimeInterval, $when: DateTime) {
} }
} }
query GetRunsLeaderboard($interval: TimeInterval, $when: DateTime) { query GetRunsLeaderboard(
getLongestRunsLeaderboard(interval: $interval, when: $when) { $interval: TimeInterval
$when: DateTime
$gameType: String
$tableSizeMin: Float
$tableSizeMax: Float
$pocketSizeMin: Float
$pocketSizeMax: Float
) {
getLongestRunsLeaderboard(
interval: $interval
when: $when
gameType: $gameType
tableSizeMin: $tableSizeMin
tableSizeMax: $tableSizeMax
pocketSizeMin: $pocketSizeMin
pocketSizeMax: $pocketSizeMax
) {
entries { entries {
id id
runLength runLength

View File

@@ -0,0 +1,25 @@
# Legacy shot-sim operations still used by mobile master's
# LiveStreamPicker / RecordedShotPicker; remove when those are deleted.
query GetRecordedStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
createdAt
screenshotUri
framesPerSecond
totalShots
owner {
id
username
profileImageUri
}
}
}
}

View File

@@ -0,0 +1,34 @@
# Lightweight listing of live (in-progress) streams for pickers like the
# Shot Lab "follow a live stream" flow. Selects only what a picker card
# needs; intentionally avoids the heavy VideoCardFields fragment.
query GetLiveStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: false, requireCursorCompletion: false }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
startTime
createdAt
screenshotUri
elapsedTime
owner {
id
username
profileImageUri
}
stream {
id
isCompleted
lastSegmentUploadedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}

View File

@@ -1,12 +1,12 @@
# Lightweight two-step picker data for Shot Lab's video-first source: recent # Lightweight two-step picker data for Shot Lab's video-first source: the
# videos (completed or still uploading — no completion gate, so an in-progress # caller's recent videos (completed or still uploading), then that video's
# recording with no shots yet still appears), then that video's shots. The # shots. The stream fields hint at "actively updating" without gating.
# stream fields let the client hint at "actively updating" without gating. query GetShotLabVideos($userId: Int!, $limit: Int! = 25) {
query GetShotLabVideos($limit: Int! = 25) {
getFeedVideos( getFeedVideos(
limit: $limit limit: $limit
includeCallersVideos: false
includePrivate: MINE includePrivate: MINE
feedInput: { allUsers: true } feedInput: { userId: $userId }
) { ) {
videos { videos {
id id
@@ -43,26 +43,11 @@ query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) {
serializedShotPaths { serializedShotPaths {
b64EncodedBuffer b64EncodedBuffer
} }
cueObjectFeatures {
cueObjectDistance
cueObjectAngle
cueBallSpeed
shotDirection
spinType
}
pocketingIntentionFeatures { pocketingIntentionFeatures {
make make
targetPocketDistance
targetPocketAngle
targetPocketAngleDirection
marginOfErrorInDegrees
intendedPocketType
difficulty
} }
pocketingIntentionInfo { pocketingIntentionInfo {
ballId
pocketId pocketId
pathMetadataIndex
} }
} }
} }

View File

@@ -20,6 +20,18 @@ query GetSessionCoach($videoId: Int!) {
candidates { candidates {
...SessionCoachCandidateFields ...SessionCoachCandidateFields
} }
agentGeneration {
...SessionCoachGenerationFields
}
}
}
mutation RequestSessionCoachGeneration($videoId: Int!) {
requestSessionCoachGeneration(videoId: $videoId) {
state
agentGeneration {
...SessionCoachGenerationFields
}
} }
} }
@@ -49,3 +61,39 @@ fragment SessionCoachCandidateFields on SessionCoachCandidateGQL {
rankReason rankReason
} }
} }
fragment SessionCoachGenerationFields on SessionCoachGenerationGQL {
id
state
createdAt
completedAt
decision {
selectedCandidateId
title
body
suggestedAction
drillId
drillReason
practiceAttemptCount
practiceTarget
}
diagnostics {
analysisVersion
promptVersion
providerKey
modelName
inputHash
attemptCount
maxAttempts
enqueueCount
latencyMs
inputTokens
cachedInputTokens
outputTokens
failureCode
updatedAt
startedAt
lastEnqueuedAt
abstentionReason
}
}

View File

@@ -131,6 +131,7 @@ query GetVideoSocialDetailsById($videoId: Int!) {
replies { replies {
id id
message message
replyToCommentId
user { user {
...UserSocialsFields ...UserSocialsFields
} }

View File

@@ -48,6 +48,7 @@ mutation GetUploadLink($videoId: Int!, $segmentIndex: Int!) {
} }
} }
stream { stream {
id
uploadCompletionCursor uploadCompletionCursor
} }
} }
@@ -127,6 +128,7 @@ fragment UploadStreamWithDetails on VideoGQL {
name name
startTime startTime
stream { stream {
id
isCompleted isCompleted
lastIntendedSegmentBound lastIntendedSegmentBound
uploadCompletionCursor uploadCompletionCursor

View File

@@ -221,6 +221,7 @@ type CommentGQL {
user: UserGQL! user: UserGQL!
message: String! message: String!
replies: [CommentGQL!]! replies: [CommentGQL!]!
replyToCommentId: Int
} }
type CountLeaderboardGQL { type CountLeaderboardGQL {
@@ -716,6 +717,7 @@ type Mutation {
shotId: Int! shotId: Int!
fieldsToEdit: EditableShotFieldInputGQL! fieldsToEdit: EditableShotFieldInputGQL!
): EditShotReturn! ): EditShotReturn!
requestSessionCoachGeneration(videoId: Int!): SessionCoachGQL!
getProfileImageUploadLink( getProfileImageUploadLink(
fileExt: String = ".png" fileExt: String = ".png"
): GetProfileUploadLinkReturn! ): GetProfileUploadLinkReturn!
@@ -1320,6 +1322,17 @@ enum SessionCoachCandidateKindEnum {
USAGE_PATTERN USAGE_PATTERN
} }
type SessionCoachDecisionGQL {
selectedCandidateId: ID
title: String
body: String
suggestedAction: String
drillId: String
drillReason: String
practiceAttemptCount: Int
practiceTarget: String
}
type SessionCoachEvidenceGQL { type SessionCoachEvidenceGQL {
bucketKey: String! bucketKey: String!
bucketLabel: String! bucketLabel: String!
@@ -1352,6 +1365,43 @@ type SessionCoachGQL {
makePercentage: Float makePercentage: Float
primaryCandidate: SessionCoachCandidateGQL primaryCandidate: SessionCoachCandidateGQL
candidates: [SessionCoachCandidateGQL!]! candidates: [SessionCoachCandidateGQL!]!
agentGeneration: SessionCoachGenerationGQL
}
type SessionCoachGenerationDiagnosticsGQL {
analysisVersion: String!
promptVersion: String!
providerKey: String!
modelName: String!
inputHash: String!
attemptCount: Int!
maxAttempts: Int!
enqueueCount: Int!
latencyMs: Int
inputTokens: Int
cachedInputTokens: Int
outputTokens: Int
failureCode: String
updatedAt: DateTime!
startedAt: DateTime
lastEnqueuedAt: DateTime
abstentionReason: String
}
type SessionCoachGenerationGQL {
id: ID!
state: SessionCoachGenerationStateEnum!
createdAt: DateTime!
completedAt: DateTime
decision: SessionCoachDecisionGQL
diagnostics: SessionCoachGenerationDiagnosticsGQL
}
enum SessionCoachGenerationStateEnum {
QUEUED
RUNNING
READY
FAILED
} }
enum SessionCoachIneligibilityReasonEnum { enum SessionCoachIneligibilityReasonEnum {
@@ -1880,7 +1930,7 @@ type VideoGQL {
startTime: DateTime startTime: DateTime
endTime: DateTime endTime: DateTime
elapsedTime: Float elapsedTime: Float
framesPerSecond: Float! framesPerSecond: Float
tableSize: Float! tableSize: Float!
pocketSize: Float pocketSize: Float
private: Boolean! private: Boolean!