{"record":{"id":"243f277bffedd906","repo":"can1357/oh-my-pi","slug":"no-session-agent-outputs-unavailable","errorCode":null,"errorMessage":"No session - agent outputs unavailable","messagePattern":"No session - agent outputs unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/agent-protocol.ts","lineNumber":68,"sourceCode":"\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\n\t\t// parked id contributes only its nested child dir, not the root dir that\n\t\t// actually holds `<id>.md` — and with two coexisting roots the global\n\t\t// `Main` ref can belong to the other root, whose dir would otherwise win\n\t\t// the first-hit id map for a shared id. No caller session file: keep the\n\t\t// pre-existing global scan untouched.\n\t\tconst dirs = artifactsDirsFromRegistry(\n\t\t\trootSessionFile ? { preferredDir: rootSessionFile.slice(0, -6) } : undefined,\n\t\t);\n\t\tif (dirs.length === 0) {\n\t\t\tthrow new Error(\"No session - agent outputs unavailable\");\n\t\t}\n\n\t\t// A subagent allocates its own children as dot-qualified ids\n\t\t// (`Parent.Child`), so the slash path form is first tried as a hierarchy\n\t\t// separator: `agent://Parent/Child` resolves `Parent.Child.md`. Only when\n\t\t// no such nested output exists does the path fall back to jq-style JSON\n\t\t// extraction on `<outputId>.md`. Query form (`?q=`) is always extraction.\n\t\tconst pathSegments = hasPathExtraction ? urlPath.split(\"/\").filter(Boolean) : [];\n\t\tconst decodedSegments = pathSegments.map(segment => {\n\t\t\ttry {\n\t\t\t\treturn decodeURIComponent(segment);\n\t\t\t} catch {\n\t\t\t\treturn segment;\n\t\t\t}\n\t\t});\n\t\tconst nestedId =\n\t\t\tdecodedSegments.length > 0 && decodedSegments.every(segment => !segment.includes(\".\"))\n\t\t\t\t? [outputId, ...decodedSegments].join(\".\")","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/agent-protocol.ts#L50-L86","documentation":"Agent outputs live in per-session artifacts directories discovered via AgentRegistry and artifactsDirsFromRegistry(). If the registry yields zero directories — meaning no session has ever been registered (optionally with the caller's sessionFile persisted via ensurePersistedRoster first) — there is nowhere to resolve the output ID and the handler throws. This is an environment/state error, not a URL-shape error.","triggerScenarios":"Calling resolve() with no registered agent sessions, or with a context.sessionFile that fails to persist a roster so no artifact dirs can be derived — artifactsDirsFromRegistry() returns an empty array.","commonSituations":"Invoking an agent:// URL resolution outside of an active session (scripts, tests, SDK usage without booting the registry); calling from a context where context.sessionFile is undefined and no global sessions exist yet; sessions that were cleaned up or whose registry state was lost after a restart.","solutions":["Ensure an agent session is registered in AgentRegistry.global() before resolving agent:// URLs","Pass a valid context.sessionFile in ResolveContext so ensurePersistedRoster can seed the artifacts dir","Verify the session artifacts directories exist on disk for the running session"],"exampleFix":"// before\nconst res = await handler.resolve(url); // no context, no sessions registered\n// after\nconst res = await handler.resolve(url, { sessionFile: \"/path/to/session.jsonl\" });","handlingStrategy":"try-catch","validationCode":"const dirs = artifactsDirsFromRegistry();\nif (dirs.length === 0) {\n  // register a session or pass context.sessionFile before resolving\n}","typeGuard":null,"tryCatchPattern":"try {\n  const resource = await handler.resolve(url, context);\n} catch (err) {\n  if (err instanceof Error && err.message === \"No session - agent outputs unavailable\") {\n    // register a session / pass context.sessionFile, then retry\n  } else throw err;\n}","preventionTips":["Always pass context.sessionFile in ResolveContext when resolving agent:// URLs","Ensure AgentRegistry.global() has at least one registered session before resolution","In tests/scripts, bootstrap a session before exercising agent:// lookups"],"tags":["session","state","agent-registry","agent-protocol"],"backgroundTag":"no-active-session","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}