mirror of
https://github.com/openai/codex.git
synced 2026-04-29 17:06:51 +00:00
Retry Agent bridge answers across framework races
Keep internal bridge requests using framework question state, distinguish bridge responses from user answers in Genie logs, and retry Agent-side bridge answers across short framework timing races instead of failing immediately. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import android.app.agent.AgentManager
|
||||
import android.app.agent.AgentService
|
||||
import android.app.agent.AgentSessionEvent
|
||||
import android.app.agent.AgentSessionInfo
|
||||
import android.os.Process
|
||||
import android.util.Log
|
||||
import org.json.JSONObject
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -12,6 +13,8 @@ import kotlin.concurrent.thread
|
||||
class CodexAgentService : AgentService() {
|
||||
companion object {
|
||||
private const val TAG = "CodexAgentService"
|
||||
private const val BRIDGE_ANSWER_RETRY_COUNT = 10
|
||||
private const val BRIDGE_ANSWER_RETRY_DELAY_MS = 50L
|
||||
private const val BRIDGE_REQUEST_PREFIX = "__codex_bridge__ "
|
||||
private const val BRIDGE_RESPONSE_PREFIX = "__codex_bridge_result__ "
|
||||
private const val METHOD_GET_AUTH_STATUS = "get_auth_status"
|
||||
@@ -110,7 +113,7 @@ class CodexAgentService : AgentService() {
|
||||
}
|
||||
|
||||
runCatching {
|
||||
manager.answerQuestion(sessionId, "$BRIDGE_RESPONSE_PREFIX$response")
|
||||
answerBridgeQuestion(manager, sessionId, "$BRIDGE_RESPONSE_PREFIX$response")
|
||||
}.onFailure { err ->
|
||||
handledBridgeRequests.remove(requestKey)
|
||||
Log.w(TAG, "Failed to answer bridge question for $sessionId", err)
|
||||
@@ -118,6 +121,21 @@ class CodexAgentService : AgentService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun answerBridgeQuestion(manager: AgentManager, sessionId: String, response: String) {
|
||||
repeat(BRIDGE_ANSWER_RETRY_COUNT) { attempt ->
|
||||
runCatching {
|
||||
manager.answerQuestion(sessionId, response)
|
||||
}.onSuccess {
|
||||
return
|
||||
}.onFailure { err ->
|
||||
if (attempt == BRIDGE_ANSWER_RETRY_COUNT - 1 || !isBridgeQuestionPending(manager, sessionId, err)) {
|
||||
throw err
|
||||
}
|
||||
Thread.sleep(BRIDGE_ANSWER_RETRY_DELAY_MS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasAnswerForRequest(events: List<AgentSessionEvent>, requestId: String): Boolean {
|
||||
return events.any { event ->
|
||||
if (event.type != AgentSessionEvent.TYPE_ANSWER || event.message == null) {
|
||||
@@ -132,4 +150,20 @@ class CodexAgentService : AgentService() {
|
||||
}.getOrNull() == requestId
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSessionWaitingForUser(manager: AgentManager, sessionId: String): Boolean {
|
||||
return manager.getSessions(Process.myUid() / 100000).any { session ->
|
||||
session.sessionId == sessionId &&
|
||||
session.state == AgentSessionInfo.STATE_WAITING_FOR_USER
|
||||
}
|
||||
}
|
||||
|
||||
private fun isBridgeQuestionPending(
|
||||
manager: AgentManager,
|
||||
sessionId: String,
|
||||
err: Throwable,
|
||||
): Boolean {
|
||||
return err.message?.contains("not waiting for user input", ignoreCase = true) == true ||
|
||||
!isSessionWaitingForUser(manager, sessionId)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user