Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
51a9a88
fix(server): poll provider usage only while visible
ElliotDrel Nov 4, 2026
22c9753
fix(server): preserve usage refresh state across surfaces
ElliotDrel Nov 4, 2026
7745561
test(server): inject the shared usage client in reset fixtures
ElliotDrel Nov 4, 2026
f7c1571
fix: address usage polling review regressions
ElliotDrel Nov 4, 2026
934fba4
fix: preserve usage freshness across cached and delayed reads
ElliotDrel Nov 4, 2026
d149f0e
fix(web): refresh usage when an instance changes driver
ElliotDrel Nov 4, 2026
f9b4f40
fix: refresh pooled accounts and retain native sample times
ElliotDrel Nov 4, 2026
0e899b9
fix(server): isolate Claude probes and retain source backoff
ElliotDrel Nov 4, 2026
bf5ee43
fix(server): discard usage successes invalidated in flight
ElliotDrel Nov 4, 2026
2a2a349
fix(server): retain quota cooldowns through OAuth renewal
ElliotDrel Nov 4, 2026
4d5df94
fix(server): retain quota identity when userinfo fails
ElliotDrel Nov 4, 2026
068dfe3
fix(server): release expired usage response snapshots
ElliotDrel Nov 4, 2026
f5bde45
test(server): assert cached Antigravity sample age
ElliotDrel Nov 4, 2026
1c3ff0c
fix(server): defer Claude resets during usage cooldowns
ElliotDrel Nov 4, 2026
29535d3
fix(server): preserve pending resets and account usage clears
ElliotDrel Nov 4, 2026
b78986c
fix(server): await quota reads and retain Claude account cooldowns
ElliotDrel Nov 4, 2026
622824c
fix: preserve Cursor cooldowns and legacy usage refreshes
ElliotDrel Nov 4, 2026
eb08226
fix(server): coordinate refreshes and share account readings
ElliotDrel Nov 4, 2026
d5ffe94
fix(server): preserve refresh order and discovered account cooldowns
ElliotDrel Nov 4, 2026
6a553d0
fix(usage): invalidate rejected credits and batch Limits refreshes
ElliotDrel Nov 5, 2026
0bbcbc6
fix(usage): seed hub command availability once at startup
ElliotDrel Nov 5, 2026
b0b37a6
fix(usage): queue Limits reads after enabling Cursor
ElliotDrel Nov 5, 2026
f795258
fix(usage): honor retained-chat visibility and Cursor sign-in
ElliotDrel Nov 5, 2026
a93758b
fix(usage): respect hidden columns and credential ownership
ElliotDrel Nov 5, 2026
aa55a91
fix(usage): preserve account identity and refresh report time
ElliotDrel Nov 5, 2026
c418632
fix(usage): retain Antigravity identity during failures
ElliotDrel Nov 5, 2026
b364bf4
fix(usage): await shared reads and recover from cancellation
ElliotDrel Nov 5, 2026
a4f2717
fix(usage): await automatic client refresh coalescing
ElliotDrel Nov 5, 2026
81a2c4a
fix(web): retain pending usage reads across remounts
ElliotDrel Nov 5, 2026
b225a28
fix(mobile): throttle visible indicator refresh restarts
ElliotDrel Nov 5, 2026
9e5069f
fix(server): use the environment service in Claude probe tests
ElliotDrel Nov 5, 2026
4838cc1
chore: merge main into usage polling fix
ElliotDrel Nov 5, 2026
87ac21e
fix(mobile): preserve usage refresh deadlines after reopening
ElliotDrel Nov 5, 2026
09ae420
chore: sync usage polling branch with main
ElliotDrel Nov 5, 2026
6809a1e
fix(codex): omit usage failures from health-only probes
ElliotDrel Nov 5, 2026
6759e6a
fix(usage): clear switched accounts and retain refresh deadlines
ElliotDrel Nov 5, 2026
6aeafd0
fix(providers): preserve usage ownership and shared refresh deadlines
ElliotDrel Nov 5, 2026
ec6e515
fix(grok): omit usage failures from health-only checks
ElliotDrel Nov 5, 2026
1e9cf3c
fix(usage): discard redeemed credits from retained hub readings
ElliotDrel Nov 5, 2026
59a0c52
fix(grok): keep supported usage commands available before polling
ElliotDrel Nov 5, 2026
3f8ca2c
fix(usage): reconcile source credit snapshots after redemption
ElliotDrel Nov 5, 2026
7c94e96
refactor(usage): retain hub readings in one service
ElliotDrel Nov 5, 2026
d73ea03
fix(usage): isolate hub ownership and preserve failed probes
ElliotDrel Nov 5, 2026
9e5889e
fix(web): share usage deadlines across entry points
ElliotDrel Nov 5, 2026
e31a4ae
fix(web): initialize shared refresh interval baselines
ElliotDrel Nov 5, 2026
9735580
Merge remote-tracking branch 'github/main' into t3/claude-usage-polling
maria-rcks Nov 5, 2026
f571073
fix(mobile): share usage deadlines between thread and Limits views
maria-rcks Nov 5, 2026
1f841f3
fix(mobile): share usage deadlines across entry points
ElliotDrel Nov 5, 2026
75c9484
fix(grok): retain quota ownership across token renewal
ElliotDrel Nov 5, 2026
80bb85e
merge: reconcile remote mobile deadline fix without duplicate caches
ElliotDrel Nov 5, 2026
f066824
merge: preserve usage polling controls with current main
ElliotDrel Nov 5, 2026
fda0613
fix(grok): preserve account cooldowns across token renewal
ElliotDrel Nov 5, 2026
597621f
fix(test): complete usage secret resolver fixtures after main merge
ElliotDrel Nov 5, 2026
6cac8d8
Merge remote-tracking branch 'github/main' into t3/claude-usage-polling
maria-rcks Nov 5, 2026
9f56e38
test(server): add secret resolver label to usage source stubs
maria-rcks Nov 5, 2026
adb5c04
fix(mobile): share widget quota deadlines with usage views
ElliotDrel Nov 5, 2026
e7ec23b
fix(server): refresh quotas before fallback routing
ElliotDrel Nov 6, 2026
470c4f8
fix(usage): preserve server quota deadlines across clients
ElliotDrel Nov 6, 2026
a782ec1
merge: preserve on-demand catalogs with usage refresh routing
ElliotDrel Nov 6, 2026
d9952ef
fix(antigravity): retain quota deadlines in direct snapshots
ElliotDrel Nov 6, 2026
7f9c061
test(server): await process lifecycle without fixture deadlines
ElliotDrel Nov 6, 2026
25fa349
Merge remote-tracking branch 'origin/main' into t3/claude-usage-polling
ElliotDrel Nov 6, 2026
7f54b79
fix(usage): skip cached health probes and hidden mobile reads
ElliotDrel Nov 6, 2026
025fdea
fix(usage): refresh client defaults and normalize remote deadlines
ElliotDrel Nov 6, 2026
39ee83b
fix(web): scope default quota demand to each draft
ElliotDrel Nov 6, 2026
0e2d2ef
fix(usage): bound default-selection quota waits
ElliotDrel Nov 6, 2026
cd28b41
test(web): use compatible deferred promises
ElliotDrel Nov 6, 2026
c19636d
fix(server): refresh quotas only for eligible fallbacks
ElliotDrel Nov 6, 2026
c1fcd04
test(server): align cold preflight expectation order
ElliotDrel Nov 6, 2026
77be7e1
fix(usage): validate saved picks and preserve quota cache deadlines
ElliotDrel Nov 6, 2026
a9e7712
fix(usage): preserve cache expiry across instances and sign-ins
ElliotDrel Nov 6, 2026
7184407
fix(usage): isolate Claude credentials and skip hidden hub reads
ElliotDrel Nov 6, 2026
4c2f73a
fix(usage): retain failure expiry and refresh after reconnects
ElliotDrel Nov 6, 2026
2b14c6e
test(mobile): supply per-environment widget presentations
ElliotDrel Nov 6, 2026
1526b96
Merge main into t3/claude-usage-polling
ElliotDrel Nov 6, 2026
701d38d
Merge remote-tracking branch 'github/main' into t3/claude-usage-polling
maria-rcks Nov 6, 2026
2029b7d
fix(server): bound quota waits before generation and launches
maria-rcks Nov 6, 2026
d1c0085
fix(usage): bound server selection quota preflights
ElliotDrel Nov 6, 2026
77a6c69
merge: preserve concurrent quota wait fixes and regressions
ElliotDrel Nov 6, 2026
48be95f
fix(server): refresh quotas only for fallback candidates
maria-rcks Nov 6, 2026
d1d2210
Merge remote-tracking branch 'fork/t3/claude-usage-polling' into t3/c…
ElliotDrel Nov 6, 2026
200576c
fix(web): keep quota waits out of draft working state
ElliotDrel Nov 6, 2026
0614dd8
fix(web): reconcile draft quota results across snapshot updates
ElliotDrel Nov 6, 2026
c1fac06
fix(usage): revalidate due quotas at client demand
ElliotDrel Nov 6, 2026
ac39762
fix(web): compile quota preflights and normalize coverage paths
ElliotDrel Nov 6, 2026
ee96852
fix(usage): advance retained hub deadlines after listing failures
ElliotDrel Nov 6, 2026
f40a6e2
fix(usage): preserve Antigravity expiry and refresh Cursor opt-in
ElliotDrel Nov 6, 2026
98d68e6
merge: integrate main while preserving usage demand guards
ElliotDrel Nov 6, 2026
b299f95
fix(usage): back off Antigravity quota demand after health failures
ElliotDrel Nov 6, 2026
48ae5a0
fix(provider): exclude external-only usage from quota deadlines
ElliotDrel Nov 6, 2026
a792901
fix(opencode): invalidate quota freshness when Go credentials change
ElliotDrel Nov 6, 2026
d6c879a
fix(usage): separate local freshness keys from workspace identity
ElliotDrel Nov 6, 2026
60d258c
fix(opencode): check quota ownership before reusing freshness
ElliotDrel Nov 6, 2026
81f8385
fix(usage): retain failed quotas when credential ownership matches
ElliotDrel Nov 6, 2026
44b3146
fix(usage): invalidate freshness on Grok account and instance changes
ElliotDrel Nov 6, 2026
565f935
Merge remote-tracking branch 'origin/main' into t3/claude-usage-polling
ElliotDrel Nov 7, 2026
d761d81
fix(usage): preserve visible provider filter after main integration
ElliotDrel Nov 7, 2026
ac58a17
fix(usage): retain cold-start command availability
ElliotDrel Nov 7, 2026
d672184
fix(mobile): pace retries of overdue usage readings
ElliotDrel Nov 7, 2026
6ba0559
fix(usage): retain owned quotas through health-only marker changes
ElliotDrel Nov 7, 2026
09a65ab
fix(grok): clear subscription quotas for unsupported auth
ElliotDrel Nov 7, 2026
febc487
test(codex): report failures before subprocess startup
ElliotDrel Nov 7, 2026
2a2863c
fix(web): pace repeated overdue quota refreshes
ElliotDrel Nov 7, 2026
43ddeaf
fix(claude): invalidate quota freshness on local account changes
ElliotDrel Nov 7, 2026
5b0afcd
fix(usage): retain expiry on synthesized cooldown responses
ElliotDrel Nov 7, 2026
e5a2d7d
fix(codex): track native quota ownership before reusing freshness
ElliotDrel Nov 7, 2026
a16e8b5
refactor(usage): remove unused pending-refresh mode
ElliotDrel Nov 7, 2026
e0d829f
fix(server): stop quota reads at the first usable fallback
ElliotDrel Nov 7, 2026
a5ed779
fix(codex): invalidate quotas when native ownership changes
ElliotDrel Nov 7, 2026
8eed9b4
fix(usage): preserve hub retry deadlines in the cache
ElliotDrel Nov 7, 2026
68c32c9
fix(usage): invalidate removed Grok auth and skip ineligible fallbacks
ElliotDrel Nov 7, 2026
5328986
merge main into usage polling branch
ElliotDrel Nov 9, 2026
ed6c671
fix(usage): preserve retry pacing and fallback eligibility
ElliotDrel Nov 9, 2026
7a6214c
fix(usage): reject switched Claude reads and preserve valid quotas
ElliotDrel Nov 9, 2026
7dbbfb7
fix(web): honor quota clears and skip explicit draft preflight
ElliotDrel Nov 9, 2026
c381084
fix(web): preserve drafts edited during quota preflight
ElliotDrel Nov 9, 2026
8262574
fix(web): revalidate draft ownership after async reads
ElliotDrel Nov 9, 2026
7db0e05
fix(mobile): preserve draft ownership and pending attachments on send
ElliotDrel Nov 9, 2026
188c4db
fix(usage): reconcile quota owners and pace native account failures
ElliotDrel Nov 9, 2026
ea18838
fix(mobile): choose draft checkout after pending attachments settle
ElliotDrel Nov 9, 2026
ab266e1
fix(usage): retain Claude cooldowns and skip quota-less adapters
ElliotDrel Nov 9, 2026
85b3e51
fix(usage): honor freshness for unsupported native accounts
ElliotDrel Nov 9, 2026
d25df08
fix(usage): invalidate cleared account quotas and scope Go preflights
ElliotDrel Nov 9, 2026
9866871
fix(usage): scope server quota preflights to relevant models
ElliotDrel Nov 9, 2026
85bf97b
merge: reconcile usage polling with current main
ElliotDrel Nov 9, 2026
fd36049
merge: resolve main model catalog refresh conflicts
ElliotDrel Nov 9, 2026
0113c42
merge: retain quota preflight and latest main project selection
ElliotDrel Nov 10, 2026
0f3b58b
merge: preserve quota ownership with main Antigravity endpoint preced…
ElliotDrel Nov 10, 2026
1dd942e
test(web): complete server mock for retained usage refresh
ElliotDrel Nov 10, 2026
d7b8bef
merge: retain project skill scans with demand-driven quota refresh
ElliotDrel Nov 10, 2026
2273363
Merge remote-tracking branch 'origin/main' into HEAD
ElliotDrel Nov 10, 2026
01a2267
test(server): retain legacy refresh preflight in skill scan mock
ElliotDrel Nov 10, 2026
d26272f
merge: preserve project provider settings with quota preflights
ElliotDrel Nov 10, 2026
281c3bb
merge: retain new hub providers with demand-driven quota caching
ElliotDrel Nov 10, 2026
f570f3c
fix: merge main while preserving demand-driven usage polling
ElliotDrel Nov 11, 2026
ebd1d28
merge: preserve OpenCode usage ownership with latest main
ElliotDrel Nov 11, 2026
aa166c1
merge: integrate latest main Claude usage accounting
ElliotDrel Nov 11, 2026
5587cac
fix(web): merge main pending-question send handling into quota preflight
ElliotDrel Nov 11, 2026
8b847e1
Merge remote-tracking branch 'origin/main' into t3/merge-main-conflic…
ElliotDrel Nov 11, 2026
687d4ee
test(server): identify native Codex quota fixtures
ElliotDrel Nov 11, 2026
45f1766
merge: preserve quota polling while integrating main
ElliotDrel Nov 11, 2026
cd82629
Merge remote-tracking branch 'origin/main' into HEAD
ElliotDrel Nov 11, 2026
1c8d785
fix: merge main to unblock usage polling typecheck
ElliotDrel Nov 11, 2026
71b4bc1
fix(server): merge main preserving Claude quota account identity
ElliotDrel Nov 11, 2026
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
88 changes: 62 additions & 26 deletions apps/mobile/src/features/threads/NewTaskDraftScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ import {

import { ComposerEditor, type ComposerEditorHandle } from "../../components/ComposerEditor";
import { composerContextImportsAtom } from "../../state/use-composer-drafts";
import { abortComposerDraftOperations } from "../../state/composerDraftOperations";
import {
abortComposerDraftOperations,
waitForComposerDraftOperations,
} from "../../state/composerDraftOperations";
import { composerContextSendBlockReason } from "../../lib/composerContext";
import { ComposerInlineControl } from "../../components/ComposerToolbar";

Expand Down Expand Up @@ -75,6 +78,7 @@ import {
} from "../../lib/modelOptions";
import { enqueueThreadOutboxMessage } from "../../state/thread-outbox";
import {
environmentConnectedAtom,
useRemoteConnections,
useRemoteEnvironmentRuntime,
} from "../../state/use-remote-environment-registry";
Expand All @@ -92,6 +96,8 @@ import {
import { incomingShareImports, useIncomingShare } from "../sharing/IncomingShareProvider";
import { idleShareFlagAtom, idleShareImportPhaseAtom } from "./incomingShareImport";
import { newTaskFlowKey } from "./new-task-flow-state";
import { serverEnvironment } from "../../state/server";
import { vcsEnvironment } from "../../state/vcs";
import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSymbol";
import { ConnectionStatusDot } from "../connection/ConnectionStatusDot";
import { appAtomRegistry } from "../../state/atom-registry";
Expand Down Expand Up @@ -247,27 +253,8 @@ export function NewTaskDraftScreen(props: {
navigation.dispatch(StackActions.replace("Home"));
}
};
const uploadStates = useAtomValue(composerAttachmentUploadsAtom);
const attachmentBlockReason = selectedProject
? composerAttachmentUploadBlockReason({
environmentId: selectedProject.environmentId,
attachments: flow.attachments,
connected: environmentConnected,
serverConfig: selectedEnvironmentServerConfig,
states: uploadStates,
})
: null;
const attachmentsUploading =
environmentConnected &&
selectedProject !== null &&
composerAttachmentsStillUploading({
environmentId: selectedProject.environmentId,
attachments: flow.attachments,
serverConfig: selectedEnvironmentServerConfig,
states: uploadStates,
});
const queuesInsteadOfStarting = !environmentConnected || attachmentsUploading;
const promptInputRef = useRef<ComposerEditorHandle>(null);
const submittingRef = useRef(false);
const loadedBranchesProjectKeyRef = useRef<string | null>(null);
const [isReturningToProjectPicker, setIsReturningToProjectPicker] = useState(false);
const incomingShare = props.incomingShareId ? getShare(props.incomingShareId) : null;
Expand Down Expand Up @@ -354,7 +341,10 @@ export function NewTaskDraftScreen(props: {
const contextImports = useAtomValue(composerContextImportsAtom);
const isImportingContext = flow.draftKey ? contextImports[flow.draftKey] === true : false;
const isComposerInteractionLocked =
isIncomingShareTransferPending || flow.submitting || isImportingContext;
isIncomingShareTransferPending ||
flow.submitting ||
isImportingContext ||
flow.switchingToEnvironmentId !== null;
const { environments, selectedEnvironmentId, switchEnvironment, switchingToEnvironmentId } = flow;
const cycleEnvironment = () => {
if (isComposerInteractionLocked) return true;
Expand Down Expand Up @@ -562,6 +552,14 @@ export function NewTaskDraftScreen(props: {
});

async function handleStart(): Promise<import("@t3tools/contracts").MessageId | null> {
if (submittingRef.current) return null;
submittingRef.current = true;
return submitDraft().finally(() => {
submittingRef.current = false;
});
}

async function submitDraft(): Promise<import("@t3tools/contracts").MessageId | null> {
const selectedProject = flow.selectedProject;
const draftKey = flow.draftKey;
if (
Expand All @@ -580,6 +578,9 @@ export function NewTaskDraftScreen(props: {
) {
return null;
}
const projectKey = flow.getSelectedProjectKey();
await waitForComposerDraftOperations(draftKey);
if (flow.getSelectedProjectKey() !== projectKey) return null;
Comment thread
ElliotDrel marked this conversation as resolved.
Resolved
const draft = getComposerDraftSnapshot(draftKey);
if (appAtomRegistry.get(composerContextImportsAtom)[draftKey]) return null;
const modelSelection =
Expand All @@ -594,7 +595,15 @@ export function NewTaskDraftScreen(props: {
const initialMessageText = draft.text.trim();

if (
attachmentBlockReason !== null ||
composerAttachmentUploadBlockReason({
environmentId: selectedProject.environmentId,
attachments: draft.attachments,
connected: appAtomRegistry.get(environmentConnectedAtom(selectedProject.environmentId)),
serverConfig: appAtomRegistry.get(
serverEnvironment.configValueAtom(selectedProject.environmentId),
),
states: appAtomRegistry.get(composerAttachmentUploadsAtom),
}) !== null ||
!modelSelection ||
(initialMessageText.length === 0 && draft.attachments.length === 0) ||
flow.submitting ||
Expand Down Expand Up @@ -650,14 +659,41 @@ export function NewTaskDraftScreen(props: {
return null;
}

const message = flow.buildPendingTaskMessage(creationMetadata, {
currentCheckoutBranch: queuesInsteadOfStarting ? null : flow.currentCheckoutBranchName,
flow.setSubmitting(true);
const message = await flow.buildPendingTaskMessage(creationMetadata, {
currentCheckoutBranch: (attachments) => {
const environmentId = selectedProject.environmentId;
if (!appAtomRegistry.get(environmentConnectedAtom(environmentId))) return null;
const uploadInput = {
environmentId,
attachments,
connected: true,
serverConfig: appAtomRegistry.get(serverEnvironment.configValueAtom(environmentId)),
states: appAtomRegistry.get(composerAttachmentUploadsAtom),
};
if (
composerAttachmentUploadBlockReason(uploadInput) ||
composerAttachmentsStillUploading(uploadInput)
)
return null;
return (
AsyncResult.getOrElse(
appAtomRegistry.get(
vcsEnvironment.status({
environmentId,
input: { cwd: selectedProject.workspaceRoot },
}),
),
() => null,
)?.refName ?? null
);
},
});
if (!message) {
flow.setSubmitting(false);
return null;
}
// Persist locally before clearing or leaving the draft; server setup runs on the thread.
flow.setSubmitting(true);
const queued = await settlePromise(() => enqueueThreadOutboxMessage(message));
flow.setSubmitting(false);
if (AsyncResult.isFailure(queued)) {
Expand Down
13 changes: 13 additions & 0 deletions apps/mobile/src/features/threads/ThreadDetailScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useInstanceLimitsRefresh } from "../usage/useInstanceLimitsRefresh";
import { ChildThreadApprovals } from "./ChildThreadApprovals";
import { useOpenThreadInspector } from "./thread-inspector-navigation";
import { useSidebarWorkspaceTabs } from "../layout/workspace/useSystemWorkspaceTabBar";
Expand Down Expand Up @@ -999,6 +1000,18 @@ function ThreadDetailBody(
usageLimitsPanel.now,
)
: null;
useInstanceLimitsRefresh(
appAtomRegistry,
props.environmentId,
props.selectedThread.modelSelection.instanceId,
props.serverConfig?.providers.find(
(provider) => provider.instanceId === props.selectedThread.modelSelection.instanceId,
)?.driver,
usageLimitsPanel !== null &&
(props.showContent ?? true) &&
activeUserInputRequestId === null &&
props.connectionStateLabel === "connected",
Comment thread
ElliotDrel marked this conversation as resolved.
Resolved
);
const showUsageLimits = (report: UsageLimitsReport | null) =>
setUsageLimitsPanel(
report === null
Expand Down
Loading
Loading