( paused: PausedExecution, )
| 126 | }; |
| 127 | |
| 128 | export const formatPausedExecution = ( |
| 129 | paused: PausedExecution, |
| 130 | ): { |
| 131 | text: string; |
| 132 | structured: Record<string, unknown>; |
| 133 | } => { |
| 134 | const req = paused.elicitationContext.request; |
| 135 | const lines: string[] = [`Execution paused: ${req.message}`]; |
| 136 | const isUrlElicitation = Predicate.isTagged(req, "UrlElicitation"); |
| 137 | const isFormElicitation = Predicate.isTagged(req, "FormElicitation"); |
| 138 | const requestedSchema = isFormElicitation ? req.requestedSchema : undefined; |
| 139 | const hasRequestedSchema = |
| 140 | requestedSchema !== undefined && Object.keys(requestedSchema).length > 0; |
| 141 | const instructions = isUrlElicitation |
| 142 | ? `The user needs to open this URL in a browser and complete the flow. After the user finishes, call the resume tool with executionId "${paused.id}" and action "accept".` |
| 143 | : hasRequestedSchema |
| 144 | ? `Ask the user for values matching requestedSchema. Then call the resume tool with executionId "${paused.id}", action "accept", and content matching requestedSchema. If the user declines, call resume with action "decline" or "cancel".` |
| 145 | : `This is a model-side confirmation gate; there is no browser form to open. Ask the user whether to approve the paused tool call. If the user approves, call the resume tool with executionId "${paused.id}" and action "accept". If the user declines, call resume with action "decline" or "cancel".`; |
| 146 | |
| 147 | if (isUrlElicitation) { |
| 148 | lines.push(`\nOpen this URL in a browser:\n${req.url}`); |
| 149 | lines.push('\nAfter the browser flow, call the resume tool with action "accept".'); |
| 150 | } else if (hasRequestedSchema) { |
| 151 | lines.push( |
| 152 | "\nAsk the user for a response matching the requested schema, then call the resume tool.", |
| 153 | ); |
| 154 | lines.push(`\nRequested schema:\n${JSON.stringify(requestedSchema, null, 2)}`); |
| 155 | } else { |
| 156 | lines.push( |
| 157 | '\nThis is a model-side confirmation gate; no browser form is waiting. Ask the user whether to approve, then call the resume tool with action "accept", "decline", or "cancel".', |
| 158 | ); |
| 159 | } |
| 160 | |
| 161 | lines.push(`\nexecutionId: ${paused.id}`); |
| 162 | lines.push(`\ninstructions: ${instructions}`); |
| 163 | |
| 164 | return { |
| 165 | text: lines.join("\n"), |
| 166 | structured: { |
| 167 | status: "waiting_for_interaction", |
| 168 | executionId: paused.id, |
| 169 | interaction: { |
| 170 | kind: isUrlElicitation ? "url" : "form", |
| 171 | message: req.message, |
| 172 | instructions, |
| 173 | address: String(paused.elicitationContext.address), |
| 174 | args: paused.elicitationContext.args, |
| 175 | ...(isUrlElicitation ? { url: req.url } : {}), |
| 176 | ...(isFormElicitation ? { requestedSchema: req.requestedSchema } : {}), |
| 177 | }, |
| 178 | }, |
| 179 | }; |
| 180 | }; |
| 181 | |
| 182 | // --------------------------------------------------------------------------- |
| 183 | // Full invoker (base + discover + describe) |
no test coverage detected