mirror of
https://github.com/openai/codex.git
synced 2026-04-24 06:35:50 +00:00
Clean up Android question handoff lifecycle
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -205,7 +205,9 @@ class CodexAgentService : AgentService() {
|
||||
val manager = agentManager ?: return
|
||||
val events = manager.getSessionEvents(session.sessionId)
|
||||
val question = findLatestQuestion(events) ?: return
|
||||
updateQuestionNotification(session, question)
|
||||
if (!isBridgeQuestion(question)) {
|
||||
AgentQuestionNotifier.cancel(this, session.sessionId)
|
||||
}
|
||||
maybeAutoAnswerGenieQuestion(session, question)
|
||||
}
|
||||
|
||||
@@ -234,26 +236,6 @@ class CodexAgentService : AgentService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateQuestionNotification(session: AgentSessionInfo, question: String) {
|
||||
if (question.isBlank()) {
|
||||
AgentQuestionNotifier.cancel(this, session.sessionId)
|
||||
return
|
||||
}
|
||||
if (isBridgeQuestion(question)) {
|
||||
AgentQuestionNotifier.cancel(this, session.sessionId)
|
||||
return
|
||||
}
|
||||
if (pendingGenieQuestions.contains(genieQuestionKey(session.sessionId, question))) {
|
||||
return
|
||||
}
|
||||
AgentQuestionNotifier.showQuestion(
|
||||
context = this,
|
||||
sessionId = session.sessionId,
|
||||
targetPackage = session.targetPackage,
|
||||
question = question,
|
||||
)
|
||||
}
|
||||
|
||||
private fun findLatestQuestion(events: List<AgentSessionEvent>): String? {
|
||||
return events.lastOrNull { event ->
|
||||
event.type == AgentSessionEvent.TYPE_QUESTION &&
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.app.agent.GenieService
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.openai.codex.bridge.DesktopSessionBootstrap
|
||||
import com.openai.codex.bridge.DetachedTargetCompat
|
||||
import com.openai.codex.bridge.FrameworkEventBridge
|
||||
import com.openai.codex.bridge.HostedCodexConfig
|
||||
import com.openai.codex.bridge.SessionExecutionSettings
|
||||
@@ -628,6 +629,13 @@ class CodexAppServerHost(
|
||||
val questions = params.optJSONArray("questions") ?: JSONArray()
|
||||
val renderedQuestion = renderAgentQuestion(questions)
|
||||
Log.i(TAG, "Requesting Agent input for ${request.sessionId}: $renderedQuestion")
|
||||
if (request.isDetachedModeAllowed) {
|
||||
runCatching {
|
||||
showDetachedTargetForUserQuestion()
|
||||
}.onFailure { err ->
|
||||
recordNonFatalObserverFailure("request_user_input/showDetachedTarget", err)
|
||||
}
|
||||
}
|
||||
publishFrameworkQuestion(renderedQuestion)
|
||||
updateFrameworkState(AgentSessionInfo.STATE_WAITING_FOR_USER)
|
||||
val answer = control.waitForUserResponse()
|
||||
@@ -999,10 +1007,34 @@ class CodexAppServerHost(
|
||||
JSONObject()
|
||||
.put("code", code)
|
||||
.put("message", message),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun showDetachedTargetForUserQuestion() {
|
||||
var result = DetachedTargetCompat.showDetachedTarget(
|
||||
callback = callback,
|
||||
sessionId = request.sessionId,
|
||||
)
|
||||
if (result.needsRecovery()) {
|
||||
publishFrameworkTrace(result.summary("show for question"))
|
||||
val recovery = DetachedTargetCompat.ensureDetachedTargetHidden(
|
||||
callback = callback,
|
||||
sessionId = request.sessionId,
|
||||
)
|
||||
publishFrameworkTrace(recovery.summary("ensure hidden for question"))
|
||||
if (recovery.isOk()) {
|
||||
result = DetachedTargetCompat.showDetachedTarget(
|
||||
callback = callback,
|
||||
sessionId = request.sessionId,
|
||||
)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
publishFrameworkTrace(result.summary("show for question"))
|
||||
}
|
||||
|
||||
private fun sendMessage(message: JSONObject) {
|
||||
synchronized(writerLock) {
|
||||
writer.write(message.toString())
|
||||
|
||||
@@ -68,6 +68,10 @@ The current repo now contains these implementation slices:
|
||||
`request_user_input` in Default mode so ambiguous delegated tasks can pause in
|
||||
real framework `WAITING_FOR_USER` state instead of guessing or emitting a
|
||||
plain-text question as a normal completion.
|
||||
- In detached mode, Genie question handoff now recovers a missing target task by
|
||||
calling `ensureDetachedTargetHidden` before retrying `showDetachedTarget`, so a
|
||||
`WAITING_FOR_USER` session keeps launcher icon/badge behavior aligned with the
|
||||
still-live framework session.
|
||||
- The Agent now auto-answers only internal bridge questions. User-facing Genie
|
||||
questions remain user-facing and are surfaced through the normal framework
|
||||
question flow, notifications, and desktop/UI answer surfaces.
|
||||
@@ -218,7 +222,11 @@ the Android Agent/Genie flow.
|
||||
- detached target ensure-hidden/show/hide/attach/close
|
||||
- typed detached frame capture with runtime-aware recovery
|
||||
- `request_user_input` bridged from hosted Codex back into AgentSDK questions
|
||||
- Agent-owned question notifications for Genie questions that need user input
|
||||
- Framework-owned question notifications for Genie questions that need user
|
||||
input; the Agent app suppresses its former duplicate notification mirror
|
||||
- Detached-mode Genie sessions now request `showDetachedTarget` before entering
|
||||
`WAITING_FOR_USER`, so HOME can keep a visible live icon while the user
|
||||
answers the question
|
||||
- Agent-mediated answers only for internal bridge questions that the user
|
||||
should never see as product-facing prompts
|
||||
- Agent planning can now use `request_user_input` to ask the user clarifying
|
||||
@@ -248,6 +256,8 @@ the Android Agent/Genie flow.
|
||||
- hosted Agent bridge for framework session APIs
|
||||
- `android/app/src/main/java/com/openai/codex/agent/MainActivity.kt`
|
||||
- Agent session UI, Agent clarification dialogs, and Agent-native auth controls
|
||||
- `android/app/src/main/java/com/openai/codex/agent/SessionDetailActivity.kt`
|
||||
- HOME/AGENT session inspection and question answering UI
|
||||
- `android/app/src/main/java/com/openai/codex/agent/AgentUserInputPrompter.kt`
|
||||
- Android dialog bridge for hosted Agent `request_user_input` calls
|
||||
- `android/genie/src/main/java/com/openai/codex/genie/CodexGenieService.kt`
|
||||
|
||||
Reference in New Issue
Block a user