{"record":{"id":"20973a84d1c86251","repo":"can1357/oh-my-pi","slug":"agent-url-requires-an-output-id-agent-id","errorCode":null,"errorMessage":"agent:// URL requires an output ID: agent://<id>","messagePattern":"agent:// URL requires an output ID: agent://<id>","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/agent-protocol.ts","lineNumber":40,"sourceCode":"import { ensurePersistedRoster } from \"../registry/persisted-agents\";\nimport { applyQuery, pathToQuery } from \"./json-query\";\nimport { artifactsDirsFromRegistry } from \"./registry-helpers\";\nimport type { InternalResource, InternalUrl, ProtocolHandler, ResolveContext, UrlCompletion } from \"./types\";\n\n/**\n * Handler for agent:// URLs.\n *\n * Resolves output IDs like \"reviewer_0\" to their artifact files,\n * with optional JSON extraction.\n */\nexport class AgentProtocolHandler implements ProtocolHandler {\n\treadonly scheme = \"agent\";\n\treadonly immutable = true;\n\n\tasync resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {\n\t\tconst outputId = url.rawHost || url.hostname;\n\t\tif (!outputId) {\n\t\t\tthrow new Error(\"agent:// URL requires an output ID: agent://<id>\");\n\t\t}\n\n\t\tconst urlPath = url.pathname;\n\t\tconst queryParam = url.searchParams.get(\"q\");\n\t\tconst hasPathExtraction = urlPath && urlPath !== \"/\" && urlPath !== \"\";\n\t\tconst hasQueryExtraction = queryParam !== null && queryParam !== \"\";\n\n\t\tif (hasPathExtraction && hasQueryExtraction) {\n\t\t\tthrow new Error(\"agent:// URL cannot combine path extraction with ?q=\");\n\t\t}\n\n\t\tconst registry = AgentRegistry.global();\n\t\tconst rootSessionFile = context?.sessionFile\n\t\t\t? await ensurePersistedRoster(registry, context.sessionFile)\n\t\t\t: undefined;\n\t\t// The caller root's canonical artifact directory (its session file minus\n\t\t// the `.jsonl` suffix) is scanned FIRST, ahead of every process-global\n\t\t// registry dir. The roster ref this refresh installs for the caller's","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/agent-protocol.ts#L22-L58","documentation":"AgentProtocolHandler.resolve() resolves agent:// URLs to stored agent output artifacts. The output ID is taken from the URL host (url.rawHost || url.hostname); if the URL has no host component, there is nothing to look up, so the handler throws immediately. This is a malformed-URL guard, not a lookup failure.","triggerScenarios":"Calling resolve() with an InternalUrl whose rawHost and hostname are both empty — e.g. 'agent://', 'agent:///foo/bar', or a URL string that was parsed such that the id landed in the path instead of the host.","commonSituations":"Hand-writing an agent:// URL and putting the id in the path so the host ends up empty (e.g. 'agent:///reviewer_0'); constructing the InternalUrl programmatically with a missing host field; template strings that interpolate an undefined/empty id before the host.","solutions":["Put the output ID in the URL host position: agent://<id> (e.g. agent://reviewer_0)","Use the path only for nested subagent ids or JSON extraction: agent://<id>/<child> or agent://<id>?q=<query>","If building the URL in code, validate the id is non-empty before constructing it"],"exampleFix":"// before\nawait handler.resolve({ host: \"\", pathname: \"/reviewer_0\" } as InternalUrl, ctx);\n// after\nawait handler.resolve({ host: \"reviewer_0\", pathname: \"\" } as InternalUrl, ctx);","handlingStrategy":"validation","validationCode":"const outputId = url.rawHost || url.hostname;\nif (!outputId) throw new Error(`agent:// URL requires an output ID: got '${url.href}'`);","typeGuard":"function hasOutputId(url: InternalUrl): boolean {\n  return Boolean(url.rawHost || url.hostname);\n}","tryCatchPattern":null,"preventionTips":["Always author agent:// URLs as agent://<id> with the id in the host position","Validate ids are non-empty before interpolating into URL templates","Use handler.complete() to get valid id values for completion UIs"],"tags":["url","validation","agent-protocol"],"backgroundTag":"missing-url-component","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}