Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
8c875ee
feat(cursor): detect inline model errors and surface warning banner
heavygee Jun 11, 2026
76901e4
fix(cursor): anchor Gemini error patterns to start of message
heavygee Jun 12, 2026
70dc793
fix(cursor): apply trimStart to all classifier patterns, not just Gemini
heavygee Jun 12, 2026
5506c07
refactor(cursor): structural-signal-first model-error detection
heavygee Jun 12, 2026
201c3ab
refactor(cursor): strip model-error detection from legacy launcher
heavygee Jun 12, 2026
b2b21e5
fix(cursor): catch model errors appended to in-flight agent text
heavygee Jun 13, 2026
2b7dfde
feat(hub): emergency-severity push notification on model errors
heavygee Jun 16, 2026
5808f83
fix(cursor): classify Error: RetriableError inline model failures
heavygee Jul 1, 2026
19ba3a6
fix(hub): send Telegram model-error as plain text
heavygee Jul 2, 2026
4d0edc4
fix(cursor): reset lastAssistantText at turn start
heavygee Jul 2, 2026
fde04dc
fix(cursor): mark RetriableError resource_exhausted as transient
Jul 14, 2026
a2e530c
fix(hub): bind model-error acknowledge to displayed atTs
Jul 16, 2026
36f3061
fix(web): render modelError events without raw JSON dump
Jul 16, 2026
ccb1aaa
fix(cursor): classify RPC [canceled] Operation aborted before abort f…
heavygee Jul 24, 2026
ab8b0d1
fix(hub): omit rawSnippet from external model-error notifications
heavygee Jul 24, 2026
1e509c6
fix(cursor): detect prior-done when Error: T shares the Done message
heavygee Jul 24, 2026
3e24c7a
fix(hub): carry forward lastModelError across sparse metadata writes
heavygee Jul 24, 2026
f4912ec
feat(hub): FCM sendModelError for model-error wrist push (#878)
heavygee Jun 17, 2026
4cfdfe4
fix(hub): share nativeGate for model-error FCM/Web Push delivery
heavygee Jul 30, 2026
b6f7536
fix(cursor): do not promote generic ACP unknown stderr to modelError
heavygee Jul 30, 2026
39fef3b
fix(cursor): require strong signatures for typed ACP stderr modelError
heavygee Jul 30, 2026
50f4c76
fix(hub,cursor): watermark after delivery; keep across inactive; slic…
heavygee Jul 30, 2026
3b2207a
fix(hub): model-error watermark requires real delivery outcomes
heavygee Jul 30, 2026
1c08375
fix(web): localize model-error session-list indicator
heavygee Jul 30, 2026
b4e27df
fix(hub): backoff model-error delivery retries off session-updated
heavygee Jul 30, 2026
fd700ea
fix(hub): deliver model-error retries when inactive; ignore obsolete …
heavygee Jul 30, 2026
f4e17e6
fix(hub,cursor): keep model-error ack across stale CLI writes; tighte…
heavygee Jul 30, 2026
9e6eeef
fix(hub): persist model-error notifiedAt across hub restarts
heavygee Aug 2, 2026
f609930
fix(hub): retry model-error notifiedAt writes on version mismatch
heavygee Aug 2, 2026
4b040d3
fix(hub): typecheck model-error notifiedAt contention mock
heavygee Aug 2, 2026
d893684
fix(hub): retry model-error ack writes on version mismatch
heavygee Aug 2, 2026
7e5e9bd
fix(hub): rehydrate undelivered model-error alerts after restart
heavygee Aug 2, 2026
f40ce7d
fix(cursor): record prompt-time model_not_found; ignore fenced Error: T:
heavygee Aug 2, 2026
71cb88a
fix(cursor): match Markdown fence opener length when stripping quotes
heavygee Aug 2, 2026
225b779
fix(cursor): restore unclosed fence text for Error: T: fallback
heavygee Aug 2, 2026
548d1fb
fix(cursor,hub): require bare fence closers; wire FCM tag onto data
heavygee Aug 2, 2026
75fea9d
fix(hub): preserve lastModelError across SessionCache row merges
heavygee Aug 2, 2026
4620448
fix(hub): recompute session metadata merge against live target row
heavygee Aug 2, 2026
e2af564
fix(cursor): split markdown fences on CRLF as well as LF
heavygee Aug 2, 2026
b35e6a0
fix(cursor): ignore CommonMark indented-code Error: T: examples
heavygee Aug 2, 2026
dbf5007
fix(cursor): treat tab-indented lines as CommonMark quoted code
heavygee Aug 2, 2026
06fc472
fix(cursor): strip CommonMark space-prefixed tab indented code
heavygee Aug 2, 2026
0202222
fix(web): show model-error and permission attention together
heavygee Aug 2, 2026
5d95801
test(web): fix lastModelError fixture shape for SessionRowSummary
heavygee Aug 2, 2026
938474c
test(web): include required path on SessionRowSummary metadata fixture
heavygee Aug 2, 2026
f3561d0
fix(model-error): identify events by eventId, not wall-clock atTs
heavygee Aug 2, 2026
dd4e618
fix(hub): require eventId on ModelErrorNotification channel fixtures
heavygee Aug 2, 2026
3bdfac4
fix(cursor): defer text model-error until prompt settles
heavygee Aug 3, 2026
acf0e65
fix(hub): stub MachineCache.expireInactive in PTY reopen tests
heavygee Aug 4, 2026
35b3710
fix(cursor): ignore user-abort canceled as modelError; slim lockfix
heavygee Aug 4, 2026
854146d
fix(cursor,hub): tighten completion-claim match; retry notifiedAt write
heavygee Aug 5, 2026
62a7ac0
fix(cursor): defer stderr modelError until prompt settles
heavygee Aug 5, 2026
df6b614
fix(cursor): slice rawSnippet from the last Error: T marker
heavygee Aug 8, 2026
cb9b812
fix(cursor,web): quota_exhausted fixture; drop idle badge arm
heavygee Aug 8, 2026
cd82e5b
fix(cursor): ignore setup/load Cannot-use-model stderr as turn alerts
heavygee Aug 8, 2026
83b2547
fix(cursor): keep specific stderr over generic transport_closed
heavygee Aug 8, 2026
42249f5
feat(cursor): bridge transient model errors with eventId gating
heavygee Aug 9, 2026
94ecf83
feat(hub): expose model-error bridge RPC and REST routes
heavygee Aug 9, 2026
db1b30f
feat(web): bridge & retry banner plus opt-in auto-bridge setting
heavygee Aug 9, 2026
947712b
fix(cursor,hub,web): harden model-error bridge gates after fold
heavygee Aug 9, 2026
93808d7
fix(cursor): restore initializeAttempts harness after #1430 rebase
heavygee Aug 9, 2026
7c2038b
fix(cursor,hub,web): bind bridge to eventId; defer recovered; hub-per…
heavygee Aug 9, 2026
7da191a
chore: drop accidental .cursor files from #987 tip
heavygee Aug 9, 2026
aa69ba7
fix(cursor,hub,web): scope auto-bridge; arm attribution on start; ref…
heavygee Aug 9, 2026
698ed5f
fix(cursor): cancel pending model-error bridges on supersede/abort
heavygee Aug 9, 2026
2d24f7e
fix(cli): unstick releaseNextWait typing in bridge lifecycle test
heavygee Aug 9, 2026
f52b15c
fix(web): fail closed when auto-bridge session sync partially fails
heavygee Aug 9, 2026
1ebfb9f
fix(web): roll back auto-bridge hub toggle if session discovery fails
heavygee Aug 9, 2026
2495a04
fix(cursor,web): drop all post-abort modelErrors; rediscover on rollback
heavygee Aug 9, 2026
94bc3af
fix(cursor): never mark bridge recovered after deliberate abort
heavygee Aug 9, 2026
ef6fbb2
fix(cli): use mutable holders for bridge-abort test release gates
heavygee Aug 9, 2026
2d791b6
fix(hub): refuse tenant auto-bridge-setting toggles with 403
heavygee Aug 9, 2026
859ec2a
fix(cursor): refuse manual bridge while a prompt is in flight
heavygee Aug 9, 2026
0671bbd
fix(cli): enqueue bridge lifecycle tests while idle
heavygee Aug 9, 2026
6ea6b54
fix(cursor): invalidate Bridge after a newer normal turn
heavygee Aug 9, 2026
fa819c7
fix(cursor): hydrate lastModelError before superseding turns
heavygee Aug 9, 2026
0ecaa6f
fix(hub): reconcile cursor auto-bridge on session-ready
heavygee Aug 9, 2026
eccef27
fix(cursor+hub): harden Bridge gates and auto-bridge fanout
heavygee Aug 9, 2026
39662dc
fix(cursor): never Bridge ahead of a newer queued user turn
heavygee Aug 9, 2026
0b7143d
fix(cursor): queue-owned Bridge provenance and exact-replay gate
heavygee Aug 9, 2026
476e619
fix(cursor): keep caller localId when Bridge provenance is queue-owned
heavygee Aug 9, 2026
5e6d3c8
fix(hub): lock auto-bridge settings apply + harden reconcile waits
heavygee Aug 10, 2026
07bbdce
fix(cursor+hub): drop stale Bridge at dequeue; retry failed auto-brid…
heavygee Aug 10, 2026
57dc1df
fix(web): keep Bridge disabled until enqueue settles
heavygee Aug 11, 2026
b7d2e90
fix(cursor+hub+web): restart auto-bridge reconcile and Bridge fail-cl…
heavygee Aug 11, 2026
81f872c
fix(hub+web): one hub setting per PUT; drop Bridge pending on disconnect
heavygee Aug 11, 2026
9d7bf3e
fix(web): include showSessionSummaryInChat in markdown-a chat fixture
heavygee Aug 12, 2026
f17e37e
fix(web): hide auto-bridge Chat setting from tenant namespaces
heavygee Aug 12, 2026
2bea7d3
fix(web): keep model-error pulse while auto-bridge is thinking
heavygee Aug 12, 2026
054b9ed
fix(web): drop duplicate showSessionSummaryInChat in markdown-a fixture
heavygee Aug 15, 2026
80dc958
fix(web): drop Bridge pending latch on Abort
heavygee Aug 15, 2026
06262bb
fix(cli): omit synthetic localId on model-error Bridge enqueue
heavygee Aug 15, 2026
7f95697
fix(cli): drop Bridge at ACP write; treat plain 429 RPC as transient
heavygee Aug 15, 2026
4fb07a1
fix(cli): drop duplicate launcher fields after auto-retry rebase
heavygee Aug 16, 2026
d68cb95
fix(cli): record modelError when tool-activity aborts Bridge retry
heavygee Aug 16, 2026
db97e93
fix(native): treat FCM model-error as a known high-urgency type
heavygee Aug 19, 2026
ffc4d7a
fix(cli): restore Bridge+soft-steer merge after upstream rebase
heavygee Aug 20, 2026
0648c56
fix(web): keep model-error pulse beside unread attention chain
heavygee Aug 20, 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import app.hapi.data.push.PushPayload
*
* - `permission_requests` — HIGH: an agent is blocked on the operator; the
* heads-up + sound interruption is the point.
* - `model_errors` — HIGH: the agent hit a model-side failure (rate limit,
* quota, crash); same urgency as a blocked permission, event-tagged so
* distinct errors do not overwrite each other.
* - `ready` — DEFAULT: the agent finished and is waiting for input.
* - `task_notifications` — DEFAULT: task completed/failed; also the bucket
* for unknown types / contract versions (never heads-up for those).
Expand All @@ -34,6 +37,13 @@ object NotificationChannels {
).apply {
description = context.getString(R.string.channel_permission_requests_desc)
},
NotificationChannel(
PushPayload.CHANNEL_MODEL_ERROR,
context.getString(R.string.channel_model_errors),
NotificationManager.IMPORTANCE_HIGH,
).apply {
description = context.getString(R.string.channel_model_errors_desc)
},
NotificationChannel(
PushPayload.CHANNEL_READY,
context.getString(R.string.channel_ready),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ object PushNotifications {
when (payload.type) {
PushType.PERMISSION_REQUEST -> addPermissionActions(context, builder, payload)
PushType.READY, PushType.TASK_NOTIFICATION -> addReplyActions(context, builder, payload)
null -> Unit
PushType.MODEL_ERROR, null -> Unit
}
}

Expand Down
2 changes: 2 additions & 0 deletions android/app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@
<!-- Push notifications (B-M4a) -->
<string name="channel_permission_requests">权限请求</string>
<string name="channel_permission_requests_desc">智能体正在等待您允许或拒绝一次工具调用</string>
<string name="channel_model_errors">模型错误</string>
<string name="channel_model_errors_desc">智能体遇到需要处理的模型侧失败</string>
<string name="channel_ready">代理就绪</string>
<string name="channel_ready_desc">智能体已完成并正在等待输入</string>
<string name="channel_task_notifications">任务通知</string>
Expand Down
2 changes: 2 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@
<!-- Push notifications (B-M4a) -->
<string name="channel_permission_requests">Permission requests</string>
<string name="channel_permission_requests_desc">An agent is waiting for you to allow or deny a tool call</string>
<string name="channel_model_errors">Model errors</string>
<string name="channel_model_errors_desc">An agent hit a model-side failure that needs attention</string>
<string name="channel_ready">Agent ready</string>
<string name="channel_ready_desc">An agent finished and is waiting for input</string>
<string name="channel_task_notifications">Task notifications</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import kotlinx.serialization.Serializable
enum class PushType(val wire: String) {
READY("ready"),
PERMISSION_REQUEST("permission-request"),
TASK_NOTIFICATION("task-notification");
TASK_NOTIFICATION("task-notification"),
MODEL_ERROR("model-error");

companion object {
fun fromWire(value: String): PushType? = entries.firstOrNull { it.wire == value }
Expand Down Expand Up @@ -75,6 +76,8 @@ data class PushPayload(
val severity: PushSeverity?,
val contractVersion: String?,
val notifySummary: PushNotifySummary?,
/** Hub coalescing tag (`FcmSendPayload.tag`), when present on the data map. */
val tag: String?,
) {

/**
Expand All @@ -95,30 +98,31 @@ data class PushPayload(
get() = isKnownContractVersion && when (type) {
PushType.PERMISSION_REQUEST -> requestId != null
PushType.READY, PushType.TASK_NOTIFICATION -> true
null -> false
PushType.MODEL_ERROR, null -> false
}

/**
* Notification channel routing: `permission_requests` (HIGH) /
* `ready` (DEFAULT) / `task_notifications` (DEFAULT). Unknown types and
* unknown contract versions land in the default-importance
* `task_notifications` bucket — never in the heads-up channel.
* `model_errors` (HIGH) / `ready` (DEFAULT) / `task_notifications`
* (DEFAULT). Unknown types and unknown contract versions land in the
* default-importance `task_notifications` bucket — never heads-up.
*/
val channelId: String
get() = when {
!isKnownContractVersion -> CHANNEL_TASK_NOTIFICATIONS
type == PushType.PERMISSION_REQUEST -> CHANNEL_PERMISSION_REQUESTS
type == PushType.MODEL_ERROR -> CHANNEL_MODEL_ERROR
type == PushType.READY -> CHANNEL_READY
else -> CHANNEL_TASK_NOTIFICATIONS
}

/**
* Coalescing tag `type-<sessionId>`: a newer push of the same type for
* the same session replaces the previous notification instead of
* stacking (mirrors the hub-side `tag` scheme it uses for Web Push).
* Coalescing tag: prefer the hub-supplied `data.tag` (event-specific
* for `model-error`) before falling back to `type-<sessionId>`.
*/
val notificationTag: String
get() = "${rawType.ifBlank { "unknown" }}-$sessionId"
get() = tag?.takeIf { it.isNotBlank() }
?: "${rawType.ifBlank { "unknown" }}-$sessionId"

/** Title to render; falls back to the session name, then a constant. */
val displayTitle: String
Expand Down Expand Up @@ -152,6 +156,7 @@ data class PushPayload(
const val CHANNEL_PERMISSION_REQUESTS = "permission_requests"
const val CHANNEL_READY = "ready"
const val CHANNEL_TASK_NOTIFICATIONS = "task_notifications"
const val CHANNEL_MODEL_ERROR = "model_errors"

private const val DEFAULT_TITLE = "HAPI"

Expand All @@ -175,6 +180,7 @@ data class PushPayload(
severity = PushSeverity.fromWire(data["severity"]),
contractVersion = data["contractVersion"]?.takeIf { it.isNotBlank() },
notifySummary = data["notifySummary"]?.let(::parseNotifySummary),
tag = data["tag"]?.takeIf { it.isNotBlank() },
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ class PushPayloadTest {
PushPayload.CHANNEL_TASK_NOTIFICATIONS,
PushPayload.parse(permissionData("type" to "task-notification"))!!.channelId,
)
assertEquals(
PushPayload.CHANNEL_MODEL_ERROR,
PushPayload.parse(
permissionData(
"type" to "model-error",
"severity" to "error",
"tag" to "model-error-11111111-2222-3333-4444-555555555555-evt-1",
)
)!!.channelId,
)
}

@Test
Expand Down Expand Up @@ -127,6 +137,51 @@ class PushPayloadTest {
)
}

@Test
fun `model-error is a known type and prefers the hub event tag`() {
val eventTag = "model-error-11111111-2222-3333-4444-555555555555-evt-1710000000000"
val payload = PushPayload.parse(
permissionData(
"type" to "model-error",
"severity" to "error",
"title" to "Rate limited",
"body" to "status 429",
"tag" to eventTag,
).minus("requestId"),
)!!

assertEquals(PushType.MODEL_ERROR, payload.type)
assertEquals("model-error", payload.rawType)
assertEquals(PushPayload.CHANNEL_MODEL_ERROR, payload.channelId)
assertEquals(eventTag, payload.notificationTag)
assertEquals(PushSeverity.ERROR, payload.severity)
assertFalse(payload.supportsActions)
}

@Test
fun `model-error without a hub tag falls back to type-sessionId`() {
val payload = PushPayload.parse(
permissionData("type" to "model-error").minus("requestId"),
)!!
assertEquals(
"model-error-11111111-2222-3333-4444-555555555555",
payload.notificationTag,
)
}

@Test
fun `distinct model-error tags do not collapse`() {
val session = "11111111-2222-3333-4444-555555555555"
val first = PushPayload.parse(
permissionData("type" to "model-error", "tag" to "model-error-$session-evt-1"),
)!!.notificationTag
val second = PushPayload.parse(
permissionData("type" to "model-error", "tag" to "model-error-$session-evt-2"),
)!!.notificationTag
assertEquals("model-error-$session-evt-1", first)
assertEquals("model-error-$session-evt-2", second)
}

// ---------------------------------------------------------- ready bodies --

@Test
Expand Down
33 changes: 33 additions & 0 deletions cli/src/agent/backends/acp/AcpSdkBackend.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,39 @@ describe('AcpSdkBackend', () => {
expect(turnCompleteIdx).toBeGreaterThan(lateIdx);
});

it('skips session/prompt when shouldSend is false after pre-prompt drain', async () => {
backendStatics.PRE_PROMPT_UPDATE_QUIET_PERIOD_MS = 1;
backendStatics.PRE_PROMPT_UPDATE_DRAIN_TIMEOUT_MS = 50;
backendStatics.UPDATE_QUIET_PERIOD_MS = 1;
backendStatics.UPDATE_DRAIN_TIMEOUT_MS = 50;
backendStatics.LATE_FLUSH_WINDOW_MS = 1;

const backend = new AcpSdkBackend({ command: 'opencode' });
const backendInternal = backend as unknown as {
transport: {
sendRequest: (...args: unknown[]) => Promise<unknown>;
close: () => Promise<void>;
} | null;
};
let sendCalls = 0;
backendInternal.transport = {
sendRequest: async () => {
sendCalls += 1;
return { stopReason: 'end_turn' };
},
close: async () => {}
};

const sent = await backend.prompt(
'session-1',
[{ type: 'text', text: 'hi' }],
() => {},
{ shouldSend: () => false }
);
expect(sent).toBe(false);
expect(sendCalls).toBe(0);
});

it('attributes pre-prompt straggler chunks to the previous turn\'s onUpdate', async () => {
backendStatics.UPDATE_QUIET_PERIOD_MS = 25;
backendStatics.UPDATE_DRAIN_TIMEOUT_MS = 200;
Expand Down
9 changes: 7 additions & 2 deletions cli/src/agent/backends/acp/AcpSdkBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,9 @@ export class AcpSdkBackend implements AgentBackend {
async prompt(
sessionId: string,
content: PromptContent[],
onUpdate: (msg: AgentMessage) => void
): Promise<void> {
onUpdate: (msg: AgentMessage) => void,
options?: { shouldSend?: () => boolean }
): Promise<boolean> {
if (!this.transport) {
throw new Error('ACP transport not initialized');
}
Expand All @@ -561,6 +562,9 @@ export class AcpSdkBackend implements AgentBackend {
);
await this.sessionUpdateQueue;
this.messageHandler?.drainBuffers();
if (options?.shouldSend && !options.shouldSend()) {
return false;
}
this.messageHandler = new AcpMessageHandler(onUpdate, {
textChunkMode: this.options.textChunkMode,
flavor: this.options.flavor,
Expand Down Expand Up @@ -655,6 +659,7 @@ export class AcpSdkBackend implements AgentBackend {
}
}
}
return true;
}

async cancelPrompt(sessionId: string): Promise<void> {
Expand Down
7 changes: 6 additions & 1 deletion cli/src/agent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ export interface AgentBackend {
setConfigOption?(sessionId: string, configId: string, value: string): Promise<void>;
getSessionModelsMetadata?(sessionId: string): AgentSessionModelsMetadata | undefined;
getThoughtLevelConfigOption?(sessionId: string): AgentSessionConfigOptionDescriptor | undefined;
prompt(sessionId: string, content: PromptContent[], onUpdate: (msg: AgentMessage) => void): Promise<void>;
prompt(
sessionId: string,
content: PromptContent[],
onUpdate: (msg: AgentMessage) => void,
options?: { shouldSend?: () => boolean }
): Promise<void | boolean>;
cancelPrompt(sessionId: string): Promise<void>;
respondToPermission(sessionId: string, request: PermissionRequest, response: PermissionResponse): Promise<void>;
onPermissionRequest(handler: (request: PermissionRequest) => void): void;
Expand Down
7 changes: 7 additions & 0 deletions cli/src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import axios from 'axios'
import type { AgentState, ClearOpencodeSessionCallbackRequest, ClearOpencodeSessionResponse, CreateMachineResponse, CreateSessionResponse, RunnerState, Machine, MachineMetadata, Metadata, Session } from '@/api/types'
import { applyHubSessionSummaryContract } from '@/modules/common/sessionSummaryInstruction'
import { setAutoBridgeTransientModelErrors } from '@/cursor/cursorModelErrorBridgePrefs'
import type { LocalResumeTarget, ResumableSession } from '@hapi/protocol'
import {
AgentStateSchema,
Expand Down Expand Up @@ -88,6 +89,9 @@ export class ApiClient {
if (typeof parsed.data.sessionSummaryContract === 'boolean') {
applyHubSessionSummaryContract(parsed.data.sessionSummaryContract)
}
if (typeof parsed.data.autoBridgeTransientModelErrors === 'boolean') {
setAutoBridgeTransientModelErrors(parsed.data.autoBridgeTransientModelErrors)
}

const raw = parsed.data.session

Expand Down Expand Up @@ -144,6 +148,9 @@ export class ApiClient {
if (typeof parsed.data.sessionSummaryContract === 'boolean') {
applyHubSessionSummaryContract(parsed.data.sessionSummaryContract)
}
if (typeof parsed.data.autoBridgeTransientModelErrors === 'boolean') {
setAutoBridgeTransientModelErrors(parsed.data.autoBridgeTransientModelErrors)
}

const raw = parsed.data.session
const metadata = (() => {
Expand Down
11 changes: 11 additions & 0 deletions cli/src/api/apiSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,17 @@ export class ApiSessionClient extends EventEmitter {
summary: string
tokensBefore?: number
estimatedTokensAfter?: number
} | {
type: 'modelError'
kind: string
transient: boolean
rawSnippet: string
priorAssistantClaimsDone: boolean
} | {
type: 'modelErrorBridged'
kind: string
auto: boolean
eventId: string
}, id?: string): void {
const content = {
role: 'agent',
Expand Down
Loading
Loading