hyperbrane 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -25
- package/dist/agent/agentClient.d.ts +5 -0
- package/dist/agent/agentClient.js +4 -0
- package/dist/agent/agentService.d.ts +9 -37
- package/dist/agent/agentService.js +62 -322
- package/dist/agent/agentStorage.d.ts +1 -20
- package/dist/agent/agentStorage.js +0 -30
- package/dist/agent/api.d.ts +80 -151
- package/dist/agent/api.js +1 -8
- package/dist/agent/client.d.ts +3 -1
- package/dist/agent/client.js +2 -3
- package/dist/agent/control.d.ts +23 -0
- package/dist/agent/control.js +479 -0
- package/dist/agent/hostTranscript.d.ts +0 -6
- package/dist/agent/hostTranscript.js +3 -14
- package/dist/agent/session/backend.d.ts +17 -32
- package/dist/agent/session/claude/home.d.ts +0 -1
- package/dist/agent/session/claude/home.js +0 -1
- package/dist/agent/session/claude/provision.d.ts +10 -0
- package/dist/agent/session/claude/provision.js +17 -0
- package/dist/agent/session/claude/transcript.d.ts +2 -7
- package/dist/agent/session/claude/transcript.js +68 -14
- package/dist/agent/session/client.d.ts +1 -10
- package/dist/agent/session/client.js +0 -3
- package/dist/agent/session/codex/provision.d.ts +14 -0
- package/dist/agent/session/codex/provision.js +25 -0
- package/dist/agent/session/fileTranscript.d.ts +6 -49
- package/dist/agent/session/fileTranscript.js +26 -82
- package/dist/agent/session/install.d.ts +5 -0
- package/dist/agent/session/install.js +35 -0
- package/dist/agent/session/sessionStorage.d.ts +4 -35
- package/dist/agent/session/sessionStorage.js +10 -16
- package/dist/agent/session/sharedConnection.d.ts +0 -8
- package/dist/agent/session/sharedConnection.js +0 -7
- package/dist/agent/session/storedTranscripts.d.ts +1 -6
- package/dist/agent/session/storedTranscripts.js +0 -3
- package/dist/agent/session/worker/jsonRpc.d.ts +2 -13
- package/dist/agent/session/worker/jsonRpc.js +2 -11
- package/dist/agent/session/worker/protocol.d.ts +26 -20
- package/dist/agent/session/worker/protocol.js +29 -18
- package/dist/agent/session/worker/workerParams.d.ts +0 -5
- package/dist/agent/session/worker/workerParams.js +14 -14
- package/dist/agent/session/workerConnection.d.ts +2 -13
- package/dist/agent/session/workerConnection.js +7 -12
- package/dist/agent/session/workerGatewayConnection.d.ts +18 -0
- package/dist/agent/session/workerGatewayConnection.js +86 -0
- package/dist/agent/vendor-types/manifest.json +87 -0
- package/dist/agent/workerBundle.d.ts +4 -19
- package/dist/agent/workerBundle.generated.js +1 -1
- package/dist/agent/workerBundle.js +3 -30
- package/dist/agent/workerReplacement.d.ts +3 -0
- package/dist/agent/workerReplacement.js +49 -0
- package/dist/cli/agent.js +31 -16
- package/dist/cli/command.d.ts +10 -11
- package/dist/cli/command.js +0 -4
- package/dist/cli/dimension.js +6 -6
- package/dist/cli/gateway.js +3 -6
- package/dist/cli/main.js +14 -31
- package/dist/cli/streamPrinter.d.ts +2 -10
- package/dist/cli/streamPrinter.js +16 -46
- package/dist/cli/table.d.ts +0 -3
- package/dist/cli/table.js +0 -4
- package/dist/dimension/api.d.ts +39 -27
- package/dist/dimension/api.js +28 -47
- package/dist/dimension/client.d.ts +5 -0
- package/dist/dimension/client.js +4 -0
- package/dist/dimension/control.d.ts +21 -0
- package/dist/dimension/control.js +328 -0
- package/dist/dimension/image.d.ts +0 -5
- package/dist/dimension/image.js +0 -8
- package/dist/dimension/imageFiles.generated.js +1 -1
- package/dist/dimension/paths.d.ts +5 -4
- package/dist/dimension/paths.js +15 -6
- package/dist/dimension/service.d.ts +8 -24
- package/dist/dimension/service.js +60 -228
- package/dist/dimension/transport-worker.d.ts +1 -0
- package/dist/dimension/transport-worker.js +151 -0
- package/dist/dimension/transportBundle.d.ts +2 -0
- package/dist/dimension/transportBundle.generated.d.ts +1 -0
- package/dist/dimension/transportBundle.generated.js +2 -0
- package/dist/dimension/transportBundle.js +4 -0
- package/dist/dimension/transportClient.d.ts +10 -0
- package/dist/dimension/transportClient.js +115 -0
- package/dist/dimension/transportProtocol.d.ts +53 -0
- package/dist/dimension/transportProtocol.js +8 -0
- package/dist/index.d.ts +5 -9
- package/dist/index.js +5 -19
- package/dist/lib/control.d.ts +8 -0
- package/dist/lib/control.js +62 -0
- package/dist/lib/docker.d.ts +0 -22
- package/dist/lib/docker.js +0 -10
- package/dist/lib/image.d.ts +0 -3
- package/dist/lib/image.js +0 -2
- package/dist/lib/jsonDirectory.d.ts +0 -13
- package/dist/lib/jsonDirectory.js +10 -15
- package/dist/lib/scriptBundle.d.ts +6 -0
- package/dist/lib/scriptBundle.js +28 -0
- package/dist/lib/sh.d.ts +2 -0
- package/dist/lib/sh.js +8 -0
- package/dist/lib/sleep.d.ts +0 -1
- package/dist/lib/sleep.js +0 -1
- package/dist/lib/streamFetch.d.ts +15 -0
- package/dist/lib/streamFetch.js +150 -0
- package/dist/lib/tar.d.ts +0 -1
- package/dist/lib/tar.js +5 -11
- package/dist/portal-gateway/api.d.ts +13 -44
- package/dist/portal-gateway/api.js +1 -3
- package/dist/portal-gateway/control.d.ts +42 -0
- package/dist/portal-gateway/control.js +657 -0
- package/dist/portal-gateway/gatewayClient.d.ts +5 -0
- package/dist/portal-gateway/gatewayClient.js +4 -0
- package/dist/portal-gateway/gatewayService.d.ts +8 -38
- package/dist/portal-gateway/gatewayService.js +68 -254
- package/dist/portal-gateway/image.d.ts +0 -1
- package/dist/portal-gateway/image.js +0 -2
- package/dist/portal-gateway/imageFiles.generated.js +2 -2
- package/dist/portal-gateway/portalClient.d.ts +5 -0
- package/dist/portal-gateway/portalClient.js +4 -0
- package/dist/portal-gateway/portalService.d.ts +5 -47
- package/dist/portal-gateway/portalService.js +19 -349
- package/dist/portal-gateway/transport-worker.d.ts +1 -0
- package/dist/portal-gateway/transport-worker.js +205 -0
- package/dist/portal-gateway/transportBundle.d.ts +2 -0
- package/dist/portal-gateway/transportBundle.generated.d.ts +1 -0
- package/dist/portal-gateway/transportBundle.generated.js +2 -0
- package/dist/portal-gateway/transportBundle.js +4 -0
- package/dist/portal-gateway/upstream.d.ts +0 -81
- package/dist/portal-gateway/upstream.js +0 -1
- package/dist/sandbox/api.d.ts +121 -187
- package/dist/sandbox/api.js +5 -7
- package/dist/sandbox/client.d.ts +2 -0
- package/dist/sandbox/client.js +4 -0
- package/dist/sandbox/data-endpoints/dataEndpoints.d.ts +13 -0
- package/dist/sandbox/data-endpoints/dataEndpoints.js +100 -0
- package/dist/sandbox/data-endpoints/firewalledPorts.d.ts +4 -0
- package/dist/sandbox/data-endpoints/firewalledPorts.js +28 -0
- package/dist/sandbox/lib/httpOverStream.d.ts +3 -0
- package/dist/sandbox/lib/httpOverStream.js +21 -0
- package/dist/sandbox/lib/remoteFileOperations.d.ts +10 -0
- package/dist/sandbox/lib/remoteFileOperations.js +70 -0
- package/dist/sandbox/lib/shellCommand.d.ts +3 -0
- package/dist/sandbox/lib/shellCommand.js +7 -0
- package/dist/sandbox/providers/boat/boatService.d.ts +2 -0
- package/dist/sandbox/providers/boat/boatService.js +321 -0
- package/dist/sandbox/providers/exedev/exeDevService.d.ts +2 -0
- package/dist/sandbox/providers/exedev/exeDevService.js +127 -0
- package/dist/sandbox/providers/exedev/exeDevToken.d.ts +1 -0
- package/dist/sandbox/providers/exedev/exeDevToken.js +54 -0
- package/dist/sandbox/providers/local/localService.d.ts +2 -0
- package/dist/sandbox/providers/local/localService.js +219 -0
- package/dist/sandbox/providers/ssh/sshService.d.ts +2 -0
- package/dist/sandbox/providers/ssh/sshService.js +82 -0
- package/dist/sandbox/providers/ssh/sshTransport.d.ts +12 -0
- package/dist/sandbox/providers/ssh/sshTransport.js +216 -0
- package/dist/sandbox/service.d.ts +2 -0
- package/dist/sandbox/service.js +18 -0
- package/dist/sandbox/storage/descriptors.d.ts +6 -0
- package/dist/sandbox/storage/descriptors.js +25 -0
- package/dist/sandbox/storage/sandboxStorage.d.ts +11 -0
- package/dist/sandbox/storage/sandboxStorage.js +42 -0
- package/dist/upstreams/anthropic.d.ts +0 -5
- package/dist/upstreams/anthropic.js +1 -8
- package/dist/upstreams/index.d.ts +2 -6
- package/dist/upstreams/index.js +0 -4
- package/dist/upstreams/openai.d.ts +0 -5
- package/dist/upstreams/openai.js +1 -13
- package/package.json +12 -4
- package/dist/agent/gatewaySignIns.d.ts +0 -5
- package/dist/agent/gatewaySignIns.js +0 -11
- package/dist/agent/session/codex/home.d.ts +0 -2
- package/dist/agent/session/codex/home.js +0 -4
- package/dist/agent/session/codex/messages.d.ts +0 -30
- package/dist/agent/session/codex/messages.js +0 -135
- package/dist/agent/session/codex/transcript.d.ts +0 -12
- package/dist/agent/session/codex/transcript.js +0 -22
- package/dist/agent/session/sdkMessages.d.ts +0 -15
- package/dist/agent/session/sdkMessages.js +0 -28
- package/dist/agent/session/workerSseConnection.d.ts +0 -31
- package/dist/agent/session/workerSseConnection.js +0 -76
- package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.d.ts +0 -10
- package/dist/agent/vendor-types/codex/app-server/AbsolutePathBuf.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.d.ts +0 -2
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputBody.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.d.ts +0 -22
- package/dist/agent/vendor-types/codex/app-server/FunctionCallOutputContentItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ImageDetail.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/ImageDetail.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.d.ts +0 -5
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationFailure.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.d.ts +0 -11
- package/dist/agent/vendor-types/codex/app-server/ImageGenerationItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.d.ts +0 -23
- package/dist/agent/vendor-types/codex/app-server/LegacyAppPathString.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/MessagePhase.d.ts +0 -7
- package/dist/agent/vendor-types/codex/app-server/MessagePhase.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/ReasoningEffort.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/SleepItem.d.ts +0 -7
- package/dist/agent/vendor-types/codex/app-server/SleepItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/WebSearchItem.d.ts +0 -14
- package/dist/agent/vendor-types/codex/app-server/WebSearchItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.d.ts +0 -3
- package/dist/agent/vendor-types/codex/app-server/serde_json/JsonValue.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/AgentMessageDelivery.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/v2/AsyncUserInputQuestion.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/v2/ByteRange.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.d.ts +0 -5
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentState.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentTool.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CollabAgentToolCallStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.d.ts +0 -19
- package/dist/agent/vendor-types/codex/app-server/v2/CommandAction.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionSource.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/CommandExecutionStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.d.ts +0 -10
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallOutputContentItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/DynamicToolCallStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.d.ts +0 -6
- package/dist/agent/vendor-types/codex/app-server/v2/FileUpdateChange.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.d.ts +0 -4
- package/dist/agent/vendor-types/codex/app-server/v2/HookPromptFragment.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppDisplayMode.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.d.ts +0 -8
- package/dist/agent/vendor-types/codex/app-server/v2/McpAppUi.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.d.ts +0 -7
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallAppContext.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.d.ts +0 -3
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallError.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.d.ts +0 -6
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallResult.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/McpToolCallStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.d.ts +0 -5
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitation.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.d.ts +0 -6
- package/dist/agent/vendor-types/codex/app-server/v2/MemoryCitationEntry.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/PatchApplyStatus.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.d.ts +0 -8
- package/dist/agent/vendor-types/codex/app-server/v2/PatchChangeKind.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.d.ts +0 -1
- package/dist/agent/vendor-types/codex/app-server/v2/SubAgentActivityKind.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/TextElement.d.ts +0 -11
- package/dist/agent/vendor-types/codex/app-server/v2/TextElement.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.d.ts +0 -215
- package/dist/agent/vendor-types/codex/app-server/v2/ThreadItem.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/UserInput.d.ts +0 -35
- package/dist/agent/vendor-types/codex/app-server/v2/UserInput.js +0 -2
- package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.d.ts +0 -14
- package/dist/agent/vendor-types/codex/app-server/v2/WebSearchAction.js +0 -2
- package/dist/cli/services.d.ts +0 -19
- package/dist/cli/services.js +0 -34
- package/dist/dimension/http.d.ts +0 -7
- package/dist/dimension/http.js +0 -77
- package/dist/dimension/storage.d.ts +0 -39
- package/dist/dimension/storage.js +0 -79
- package/dist/portal-gateway/fakes.d.ts +0 -3
- package/dist/portal-gateway/fakes.js +0 -11
- package/dist/portal-gateway/gatewayStorage.d.ts +0 -66
- package/dist/portal-gateway/gatewayStorage.js +0 -125
- package/dist/portal-gateway/portalStorage.d.ts +0 -34
- package/dist/portal-gateway/portalStorage.js +0 -44
- package/dist/sandbox/boatService.d.ts +0 -52
- package/dist/sandbox/boatService.js +0 -343
- package/dist/sandbox/containerService.d.ts +0 -15
- package/dist/sandbox/containerService.js +0 -184
- package/dist/sandbox/endpointProxy.d.ts +0 -90
- package/dist/sandbox/endpointProxy.js +0 -716
- package/dist/sandbox/exeDevAuth.d.ts +0 -16
- package/dist/sandbox/exeDevAuth.js +0 -49
- package/dist/sandbox/localService.d.ts +0 -19
- package/dist/sandbox/localService.js +0 -200
- package/dist/sandbox/sseConnection.d.ts +0 -41
- package/dist/sandbox/sseConnection.js +0 -166
- package/dist/sandbox/sshService.d.ts +0 -30
- package/dist/sandbox/sshService.js +0 -680
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { installPackage, installedPackage, pinnedVersion } from "../install.js";
|
|
3
|
+
export const CLAUDE_SDK_PACKAGE = "@anthropic-ai/claude-agent-sdk";
|
|
4
|
+
export function claudePackage() {
|
|
5
|
+
return { pkg: CLAUDE_SDK_PACKAGE, version: pinnedVersion("claude", CLAUDE_SDK_PACKAGE), executables: `${CLAUDE_SDK_PACKAGE}-linux-*/claude` };
|
|
6
|
+
}
|
|
7
|
+
export function installClaude(installDir) {
|
|
8
|
+
return installPackage(installDir, CLAUDE_SDK_PACKAGE, pinnedVersion("claude", CLAUDE_SDK_PACKAGE), () => claudeExecutable(installDir));
|
|
9
|
+
}
|
|
10
|
+
export function installedClaude(installDir) {
|
|
11
|
+
return installedPackage(installDir, CLAUDE_SDK_PACKAGE, pinnedVersion("claude", CLAUDE_SDK_PACKAGE), () => claudeExecutable(installDir));
|
|
12
|
+
}
|
|
13
|
+
export function claudeExecutable(installDir) {
|
|
14
|
+
const base = `${installDir}/node_modules/${CLAUDE_SDK_PACKAGE}-linux-${process.arch}`;
|
|
15
|
+
const glibc = `${base}/claude`;
|
|
16
|
+
return existsSync(glibc) ? glibc : `${base}-musl/claude`;
|
|
17
|
+
}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import type { AgentTranscriptMessage } from "../../api.ts";
|
|
2
2
|
import type { TranscriptSource } from "../backend.ts";
|
|
3
3
|
import { type FileTranscript, type TranscriptLayout } from "../fileTranscript.ts";
|
|
4
|
-
/**
|
|
5
|
-
* The conversation from claude's own session file, <config>/projects/<cwd>/<session>.jsonl. Its user
|
|
6
|
-
* and assistant entries are the messages the stream carried, with their uuids (claude keeps the one
|
|
7
|
-
* a prompt was sent with); the rest (attachments, queue bookkeeping, a subagent's sidechain, meta
|
|
8
|
-
* notes) isn't the conversation.
|
|
9
|
-
*/
|
|
10
4
|
export declare function claudeTranscript({ nativeId, env, files }: TranscriptSource): FileTranscript;
|
|
11
|
-
|
|
5
|
+
export declare function claudeSubagentTranscript(source: TranscriptSource, agentId: string, toolUseId: string): FileTranscript;
|
|
6
|
+
export declare function claudeFindSubagent(source: TranscriptSource, toolUseId: string): Promise<string | null>;
|
|
12
7
|
export declare const CLAUDE_TRANSCRIPT_LAYOUT: TranscriptLayout;
|
|
13
8
|
export declare function claudeLineMessages(line: unknown): AgentTranscriptMessage[];
|
|
@@ -1,29 +1,83 @@
|
|
|
1
|
-
import { createFileTranscript, locateTranscript } from "../fileTranscript.js";
|
|
2
|
-
/**
|
|
3
|
-
* The conversation from claude's own session file, <config>/projects/<cwd>/<session>.jsonl. Its user
|
|
4
|
-
* and assistant entries are the messages the stream carried, with their uuids (claude keeps the one
|
|
5
|
-
* a prompt was sent with); the rest (attachments, queue bookkeeping, a subagent's sidechain, meta
|
|
6
|
-
* notes) isn't the conversation.
|
|
7
|
-
*/
|
|
1
|
+
import { createFileTranscript, directoryNames, locateTranscript } from "../fileTranscript.js";
|
|
8
2
|
export function claudeTranscript({ nativeId, env, files }) {
|
|
9
|
-
|
|
10
|
-
return createFileTranscript(files, () => locateTranscript(files, home, CLAUDE_TRANSCRIPT_LAYOUT, nativeId), claudeLineMessages, CLAUDE_TRANSCRIPT_LAYOUT);
|
|
3
|
+
return createFileTranscript(files, () => locateTranscript(files, claudeHome(env), CLAUDE_TRANSCRIPT_LAYOUT, nativeId), claudeLineMessages, CLAUDE_TRANSCRIPT_LAYOUT);
|
|
11
4
|
}
|
|
12
|
-
|
|
5
|
+
export function claudeSubagentTranscript(source, agentId, toolUseId) {
|
|
6
|
+
return subagentFile(source, `agent-${agentId}.jsonl`, toolUseId);
|
|
7
|
+
}
|
|
8
|
+
export async function claudeFindSubagent(source, toolUseId) {
|
|
9
|
+
const isResult = (message) => message.type === "user" && Array.isArray(message.message.content) && message.message.content.some((block) => block.type === "tool_result" && block.tool_use_id === toolUseId);
|
|
10
|
+
let found = await claudeTranscript(source).find(isResult);
|
|
11
|
+
const dir = found ? null : await subagentsDirectory(source);
|
|
12
|
+
const names = dir ? ((await directoryNames(source.files, dir)) ?? []) : [];
|
|
13
|
+
for (const name of names.filter((entry) => SUBAGENT_FILE.test(entry))) {
|
|
14
|
+
found = await subagentFile(source, name, toolUseId).find(isResult);
|
|
15
|
+
if (found)
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
const agentId = found?.tool_use_result?.agentId;
|
|
19
|
+
return typeof agentId === "string" ? agentId : null;
|
|
20
|
+
}
|
|
21
|
+
function subagentFile(source, name, toolUseId) {
|
|
22
|
+
async function locate() {
|
|
23
|
+
const dir = await subagentsDirectory(source);
|
|
24
|
+
if (!dir)
|
|
25
|
+
return null;
|
|
26
|
+
return (await directoryNames(source.files, dir))?.includes(name) ? `${dir}/${name}` : null;
|
|
27
|
+
}
|
|
28
|
+
return createFileTranscript(source.files, locate, (line) => lineMessages(line, toolUseId), CLAUDE_TRANSCRIPT_LAYOUT);
|
|
29
|
+
}
|
|
30
|
+
async function subagentsDirectory({ nativeId, env, files }) {
|
|
31
|
+
const main = await locateTranscript(files, claudeHome(env), CLAUDE_TRANSCRIPT_LAYOUT, nativeId);
|
|
32
|
+
return main ? `${main.slice(0, -".jsonl".length)}/subagents` : null;
|
|
33
|
+
}
|
|
34
|
+
function claudeHome(env) {
|
|
35
|
+
return env.CLAUDE_CONFIG_DIR ?? `${env.HOME}/.claude`;
|
|
36
|
+
}
|
|
37
|
+
const SUBAGENT_FILE = /^agent-.+\.jsonl$/;
|
|
13
38
|
export const CLAUDE_TRANSCRIPT_LAYOUT = {
|
|
14
39
|
dir: "projects",
|
|
15
40
|
depth: 2,
|
|
16
41
|
name: "{id}.jsonl",
|
|
17
42
|
time: "timestamp",
|
|
18
|
-
// Resuming a session, claude writes what it said since its last compaction again, from that compaction's line.
|
|
19
43
|
copies: '"subtype":"compact_boundary"',
|
|
20
44
|
};
|
|
21
45
|
export function claudeLineMessages(line) {
|
|
46
|
+
return lineMessages(line, null);
|
|
47
|
+
}
|
|
48
|
+
function lineMessages(line, parentToolUseId) {
|
|
22
49
|
const entry = line;
|
|
50
|
+
if (entry.type === "system" && entry.subtype === "compact_boundary")
|
|
51
|
+
return compaction(entry);
|
|
23
52
|
if (entry.type !== "user" && entry.type !== "assistant")
|
|
24
53
|
return [];
|
|
25
|
-
if (entry.isSidechain || entry.isMeta || !entry.uuid || !entry.message)
|
|
54
|
+
if ((entry.isSidechain && parentToolUseId === null) || entry.isMeta || !entry.uuid || !entry.message)
|
|
55
|
+
return [];
|
|
56
|
+
const common = { parent_tool_use_id: parentToolUseId, uuid: entry.uuid, session_id: entry.sessionId ?? "", ...(entry.timestamp ? { timestamp: entry.timestamp } : {}) };
|
|
57
|
+
if (entry.type === "assistant")
|
|
58
|
+
return [{ type: "assistant", message: entry.message, ...common }];
|
|
59
|
+
return [{ type: "user", message: entry.message, ...common, ...(entry.toolUseResult !== undefined ? { tool_use_result: entry.toolUseResult } : {}) }];
|
|
60
|
+
}
|
|
61
|
+
function compaction(entry) {
|
|
62
|
+
const meta = entry.compactMetadata;
|
|
63
|
+
if (!entry.uuid || !meta?.trigger)
|
|
26
64
|
return [];
|
|
27
|
-
|
|
28
|
-
return [
|
|
65
|
+
const { preservedSegment: segment, preservedMessages: preserved } = meta;
|
|
66
|
+
return [
|
|
67
|
+
{
|
|
68
|
+
type: "system",
|
|
69
|
+
subtype: "compact_boundary",
|
|
70
|
+
compact_metadata: {
|
|
71
|
+
trigger: meta.trigger,
|
|
72
|
+
pre_tokens: meta.preTokens ?? 0,
|
|
73
|
+
...(meta.postTokens !== undefined ? { post_tokens: meta.postTokens } : {}),
|
|
74
|
+
...(meta.durationMs !== undefined ? { duration_ms: meta.durationMs } : {}),
|
|
75
|
+
...(segment ? { preserved_segment: { head_uuid: segment.headUuid, anchor_uuid: segment.anchorUuid, tail_uuid: segment.tailUuid } } : {}),
|
|
76
|
+
...(preserved ? { preserved_messages: { anchor_uuid: preserved.anchorUuid, uuids: preserved.uuids } } : {}),
|
|
77
|
+
},
|
|
78
|
+
uuid: entry.uuid,
|
|
79
|
+
session_id: entry.sessionId ?? "",
|
|
80
|
+
...(entry.timestamp ? { timestamp: entry.timestamp } : {}),
|
|
81
|
+
},
|
|
82
|
+
];
|
|
29
83
|
}
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import type { AgentStreamingMessage } from "../api.ts";
|
|
2
2
|
import type { WorkerMethod, WorkerRequests } from "./worker/protocol.ts";
|
|
3
3
|
import type { ConnectWorker } from "./workerConnection.ts";
|
|
4
|
-
/**
|
|
5
|
-
* The worker's protocol (protocol.ts). Errors come back as the Agent*Error they were.
|
|
6
|
-
*
|
|
7
|
-
* @sealed
|
|
8
|
-
*/
|
|
4
|
+
/** @sealed */
|
|
9
5
|
export type WorkerClient = {
|
|
10
6
|
call<M extends WorkerMethod>(method: M, params: WorkerRequests[M][0]): Promise<WorkerRequests[M][1]>;
|
|
11
|
-
/**
|
|
12
|
-
* The session's messages after `afterId`, then each one as the worker produces it, over a
|
|
13
|
-
* connection held open while the caller reads. Throws once the worker goes away.
|
|
14
|
-
*/
|
|
15
7
|
stream(sessionName: string, afterId: string | undefined): AsyncGenerator<AgentStreamingMessage>;
|
|
16
8
|
};
|
|
17
|
-
/** Calls the worker over the connections `connect` opens (workerSocketConnector: its unix socket). */
|
|
18
9
|
export declare function createWorkerClient(connect: ConnectWorker): WorkerClient;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
/** Calls the worker over the connections `connect` opens (workerSocketConnector: its unix socket). */
|
|
2
1
|
export function createWorkerClient(connect) {
|
|
3
|
-
/** One request on a connection of its own. */
|
|
4
2
|
async function call(method, params) {
|
|
5
3
|
const connection = await connect();
|
|
6
4
|
try {
|
|
@@ -37,7 +35,6 @@ export function createWorkerClient(connect) {
|
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
finally {
|
|
40
|
-
// On a shared connection (sharedConnector) the worker would go on sending to it otherwise.
|
|
41
38
|
if (!ended)
|
|
42
39
|
connection.request("session/unsubscribe", { subscription }).catch(() => { });
|
|
43
40
|
connection.close();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentBackendInfo } from "../../api.ts";
|
|
2
|
+
export declare const CODEX_PACKAGE = "@openai/codex";
|
|
3
|
+
export declare function codexPackage(): {
|
|
4
|
+
pkg: string;
|
|
5
|
+
version: string;
|
|
6
|
+
executables: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function installCodex(installDir: string): Promise<void>;
|
|
9
|
+
export declare function installedCodex(installDir: string): Promise<Omit<AgentBackendInfo, "backend">>;
|
|
10
|
+
export type CodexExecutable = {
|
|
11
|
+
path: string;
|
|
12
|
+
env: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
export declare function codexExecutable(installDir: string): CodexExecutable;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { installPackage, installedPackage, pinnedVersion } from "../install.js";
|
|
2
|
+
export const CODEX_PACKAGE = "@openai/codex";
|
|
3
|
+
const CODEX_VERSION = () => pinnedVersion("codex", CODEX_PACKAGE, "@openai/codex-sdk");
|
|
4
|
+
export function codexPackage() {
|
|
5
|
+
return { pkg: CODEX_PACKAGE, version: CODEX_VERSION(), executables: "@openai/codex-linux-*/vendor/*/bin/codex" };
|
|
6
|
+
}
|
|
7
|
+
export function installCodex(installDir) {
|
|
8
|
+
return installPackage(installDir, CODEX_PACKAGE, CODEX_VERSION(), () => codexExecutable(installDir).path);
|
|
9
|
+
}
|
|
10
|
+
export function installedCodex(installDir) {
|
|
11
|
+
return installedPackage(installDir, CODEX_PACKAGE, CODEX_VERSION(), () => codexExecutable(installDir).path);
|
|
12
|
+
}
|
|
13
|
+
const LINUX_TARGETS = {
|
|
14
|
+
x64: { pkg: "@openai/codex-linux-x64", triple: "x86_64-unknown-linux-musl" },
|
|
15
|
+
arm64: { pkg: "@openai/codex-linux-arm64", triple: "aarch64-unknown-linux-musl" },
|
|
16
|
+
};
|
|
17
|
+
export function codexExecutable(installDir) {
|
|
18
|
+
const target = LINUX_TARGETS[process.arch];
|
|
19
|
+
if (process.platform !== "linux" || !target)
|
|
20
|
+
throw new Error(`codex: unsupported platform ${process.platform}/${process.arch}`);
|
|
21
|
+
return {
|
|
22
|
+
path: `${installDir}/node_modules/${target.pkg}/vendor/${target.triple}/bin/codex`,
|
|
23
|
+
env: { CODEX_MANAGED_PACKAGE_ROOT: `${installDir}/node_modules/${CODEX_PACKAGE}`, CODEX_MANAGED_BY_BUN: "1" },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -1,44 +1,22 @@
|
|
|
1
1
|
import { type SandboxFileOperations } from "../../sandbox/api.ts";
|
|
2
2
|
import { type AgentTranscriptMessage as TranscriptMessage, type AgentTranscriptPage, type AgentTranscriptRequest } from "../api.ts";
|
|
3
|
-
/** One page of a transcript: its messages oldest first, and the time the next (older) page is before. */
|
|
4
3
|
export type TranscriptPage = {
|
|
5
4
|
messages: TranscriptMessage[];
|
|
6
5
|
nextBefore: string | null;
|
|
7
6
|
};
|
|
8
|
-
|
|
9
|
-
* A backend's transcript, read from its own JSONL file a chunk at a time, so a long conversation (a
|
|
10
|
-
* file of hundreds of MB) never has to be in memory: a page holds its messages and a few chunks, and
|
|
11
|
-
* a replay streams. Pages go by the time on each line: the file is in conversation order, its times
|
|
12
|
-
* nearly so (a line is written when its message completes, so parallel branches land seconds out of
|
|
13
|
-
* order), which lets a time be found by bisecting the file.
|
|
14
|
-
*/
|
|
15
|
-
export interface FileTranscript {
|
|
16
|
-
/**
|
|
17
|
-
* The newest `limit` or so messages from before `before` (epoch ms; null for the newest), by their
|
|
18
|
-
* times, with every other message of the oldest one's time, so the page before it is exactly those
|
|
19
|
-
* before that time. `found`: what a search of the file found beforehand.
|
|
20
|
-
*/
|
|
7
|
+
export interface Transcript {
|
|
21
8
|
page(before: number | null, limit: number, found?: TranscriptFound): Promise<TranscriptPage>;
|
|
22
|
-
/**
|
|
23
|
-
* Hands `emit` every message after the one whose uuid is `afterId` (all of them when undefined), in
|
|
24
|
-
* order, as far as the file went when the replay began. False when `afterId` isn't in the file.
|
|
25
|
-
*/
|
|
26
9
|
replay(afterId: string | undefined, emit: (message: TranscriptMessage) => void): Promise<boolean>;
|
|
27
10
|
}
|
|
28
|
-
|
|
11
|
+
export type FileTranscript = Transcript & {
|
|
12
|
+
find(match: (message: TranscriptMessage) => boolean): Promise<TranscriptMessage | null>;
|
|
13
|
+
};
|
|
29
14
|
export type TranscriptFiles = {
|
|
30
15
|
size(path: string): Promise<number>;
|
|
31
16
|
readFileRange(path: string, start: number, end: number): Promise<Uint8Array>;
|
|
32
17
|
listDirectory(path: string): Promise<string[]>;
|
|
33
18
|
};
|
|
34
19
|
export declare function sandboxFiles(sandbox: SandboxFileOperations): TranscriptFiles;
|
|
35
|
-
/**
|
|
36
|
-
* Where a backend keeps its conversations, under its home: in `dir`, `depth` levels down (1: in
|
|
37
|
-
* `dir` itself), a file named `name`, where `*` is any characters and `{id}` the conversation's id.
|
|
38
|
-
* Each line of it is a JSON object with its ISO 8601 time in the field `time`. `copies`: what's in
|
|
39
|
-
* the line that starts a stretch the backend writes again (claude, resuming a session, writes what
|
|
40
|
-
* it said since its last compaction again, under the same ids and times), as it's written.
|
|
41
|
-
*/
|
|
42
20
|
export type TranscriptLayout = {
|
|
43
21
|
dir: string;
|
|
44
22
|
depth: number;
|
|
@@ -46,46 +24,25 @@ export type TranscriptLayout = {
|
|
|
46
24
|
time: string;
|
|
47
25
|
copies?: string;
|
|
48
26
|
};
|
|
49
|
-
/** A stretch of the file a reader passes over, from one line's start to another's. */
|
|
50
27
|
export type Skip = {
|
|
51
28
|
start: number;
|
|
52
29
|
end: number;
|
|
53
30
|
};
|
|
54
|
-
/** What a search of the file found beforehand (the host's, in the same round trip as the record). */
|
|
55
31
|
export type TranscriptFound = {
|
|
56
|
-
/** Where the page starts: FileTranscript.page's `before`, found. */
|
|
57
32
|
end: number;
|
|
58
|
-
/** The time of the first timed line from `end` on, if any. */
|
|
59
33
|
after: number | null;
|
|
60
|
-
/** The stretches written again. */
|
|
61
34
|
copies: Skip[];
|
|
62
35
|
};
|
|
63
|
-
/** The file of conversation `nativeId` laid out as `layout` under `home`; null when there's none yet. */
|
|
64
36
|
export declare function locateTranscript(files: TranscriptFiles, home: string, layout: TranscriptLayout, nativeId: string): Promise<string | null>;
|
|
65
|
-
/** The messages one line of the file stands for, oldest first (none for bookkeeping lines). */
|
|
66
37
|
export type LineMessages = (entry: unknown) => TranscriptMessage[];
|
|
67
|
-
/** How much of the file is read at a time. */
|
|
68
38
|
export declare const CHUNK_BYTES: number;
|
|
69
|
-
/**
|
|
70
|
-
* How far out of time order lines get, nearly always (parallel branches completing; in long claude
|
|
71
|
-
* sessions half are within 2s, 99% within a minute): searches allow for this much.
|
|
72
|
-
*/
|
|
73
39
|
export declare const TIME_SLACK_MS = 60000;
|
|
74
|
-
/** How many timed lines a probe of the bisection looks at: the earliest wins, so one odd line can't mislead it. */
|
|
75
40
|
export declare const PROBE_LINES = 3;
|
|
76
|
-
/** How much a probe reads, at most, before it gives up on finding a timed line (huge tool outputs). */
|
|
77
41
|
export declare const PROBE_BYTES: number;
|
|
78
|
-
/** `locate` finds the file; null when there's none yet (nothing stored). */
|
|
79
42
|
export declare function createFileTranscript(files: TranscriptFiles, locate: () => Promise<string | null>, lineMessages: LineMessages, layout: Pick<TranscriptLayout, "time" | "copies">): FileTranscript;
|
|
80
|
-
|
|
81
|
-
export declare function transcriptPage(transcript: FileTranscript | null, { limit, before, cursor }?: AgentTranscriptRequest, found?: TranscriptFound): Promise<AgentTranscriptPage>;
|
|
82
|
-
/** AgentTranscriptRequest.before as epoch ms; null for none. */
|
|
43
|
+
export declare function transcriptPage(transcript: Transcript | null, { limit, before, cursor }?: AgentTranscriptRequest, found?: TranscriptFound): Promise<AgentTranscriptPage>;
|
|
83
44
|
export declare function transcriptTime(before: string | undefined): number | null;
|
|
84
|
-
|
|
85
|
-
* `files` with what was already fetched of the file at `path` in the same round trip: its size, and
|
|
86
|
-
* pieces of it (what a page reads, mostly). Reading back beyond them (a page across huge tool
|
|
87
|
-
* outputs) fetches twice as much as the time before, so it takes a few more reads, not one per chunk.
|
|
88
|
-
*/
|
|
45
|
+
export declare function directoryNames(files: TranscriptFiles, dir: string): Promise<string[] | null>;
|
|
89
46
|
export declare function prefetchedFiles(files: TranscriptFiles, path: string, size: number, pieces: {
|
|
90
47
|
start: number;
|
|
91
48
|
bytes: Uint8Array;
|
|
@@ -7,40 +7,25 @@ export function sandboxFiles(sandbox) {
|
|
|
7
7
|
listDirectory: (path) => sandbox.listDirectory(path),
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
|
-
/** The file of conversation `nativeId` laid out as `layout` under `home`; null when there's none yet. */
|
|
11
10
|
export function locateTranscript(files, home, layout, nativeId) {
|
|
12
11
|
const escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13
12
|
const [before = "", after = ""] = layout.name.split("{id}").map((part) => part.split("*").map(escape).join(".*"));
|
|
14
13
|
const name = new RegExp(`^${before}${escape(nativeId)}${after}$`);
|
|
15
14
|
return findFile(files, `${home}/${layout.dir}`, layout.depth, (entry) => name.test(entry));
|
|
16
15
|
}
|
|
17
|
-
/** How much of the file is read at a time. */
|
|
18
16
|
export const CHUNK_BYTES = 64 * 1024;
|
|
19
|
-
/**
|
|
20
|
-
* How far out of time order lines get, nearly always (parallel branches completing; in long claude
|
|
21
|
-
* sessions half are within 2s, 99% within a minute): searches allow for this much.
|
|
22
|
-
*/
|
|
23
17
|
export const TIME_SLACK_MS = 60_000;
|
|
24
|
-
/** How many timed lines a probe of the bisection looks at: the earliest wins, so one odd line can't mislead it. */
|
|
25
18
|
export const PROBE_LINES = 3;
|
|
26
|
-
/** How much a probe reads, at most, before it gives up on finding a timed line (huge tool outputs). */
|
|
27
19
|
export const PROBE_BYTES = 4 * CHUNK_BYTES;
|
|
28
20
|
const NEWLINE = 0x0a;
|
|
29
|
-
/** A line's time (epoch ms) from its `field`, null without a valid one. */
|
|
30
21
|
function lineTime(entry, field) {
|
|
31
22
|
const value = entry?.[field];
|
|
32
23
|
const time = typeof value === "string" ? Date.parse(value) : NaN;
|
|
33
24
|
return Number.isNaN(time) ? null : time;
|
|
34
25
|
}
|
|
35
|
-
/** How much is read at a time when searching the whole file for where stretches were written again. */
|
|
36
26
|
const SCAN_BYTES = 1024 * 1024;
|
|
37
|
-
/**
|
|
38
|
-
* The stretches written again in the files searched last, by path and size: a search reads the whole
|
|
39
|
-
* file, and a file the backend only appends to that hasn't grown has the same ones.
|
|
40
|
-
*/
|
|
41
27
|
const searchedCopies = new Map();
|
|
42
28
|
const SEARCHED_FILES = 16;
|
|
43
|
-
/** `locate` finds the file; null when there's none yet (nothing stored). */
|
|
44
29
|
export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
45
30
|
function parse(bytes, start) {
|
|
46
31
|
try {
|
|
@@ -48,11 +33,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
48
33
|
return { start, time: lineTime(entry, layout.time), messages: lineMessages(entry) };
|
|
49
34
|
}
|
|
50
35
|
catch {
|
|
51
|
-
// A line still being written (the last one), or one this reader doesn't know: nothing in it.
|
|
52
36
|
return { start, time: null, messages: [] };
|
|
53
37
|
}
|
|
54
38
|
}
|
|
55
|
-
/** The stretches between `from` and `to` that aren't skipped, in order. */
|
|
56
39
|
function kept(from, to, skip) {
|
|
57
40
|
const parts = [];
|
|
58
41
|
let start = from;
|
|
@@ -67,14 +50,12 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
67
50
|
parts.push({ start, end: to });
|
|
68
51
|
return parts;
|
|
69
52
|
}
|
|
70
|
-
/** The file's lines before byte `end`, last first, read a chunk at a time, passing over `skip`. */
|
|
71
53
|
async function* backward(path, end, skip = []) {
|
|
72
54
|
for (const part of kept(0, end, skip).reverse())
|
|
73
55
|
yield* backwardIn(path, part.start, part.end);
|
|
74
56
|
}
|
|
75
57
|
async function* backwardIn(path, floor, end) {
|
|
76
58
|
let position = end;
|
|
77
|
-
// Bytes of a line that runs on into what was read before (later in the file).
|
|
78
59
|
let carry = new Uint8Array(0);
|
|
79
60
|
while (position > floor) {
|
|
80
61
|
const from = Math.max(floor, position - CHUNK_BYTES);
|
|
@@ -94,7 +75,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
94
75
|
if (carry.length > 0)
|
|
95
76
|
yield parse(carry, floor);
|
|
96
77
|
}
|
|
97
|
-
/** The file's lines from byte `start` to byte `end`, in order, read a chunk at a time, passing over `skip`. */
|
|
98
78
|
async function* forward(path, start, end, skip = []) {
|
|
99
79
|
for (const part of kept(start, end, skip))
|
|
100
80
|
yield* forwardIn(path, part.start, part.end);
|
|
@@ -121,15 +101,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
121
101
|
if (carry.length > 0)
|
|
122
102
|
yield parse(carry, carryStart);
|
|
123
103
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Where the lines from time `target` on start, about, between `low` and `high`: the start of a line
|
|
126
|
-
* (or `high`) with only lines from before it, allowing for the slack, ahead of it. Bisects, each
|
|
127
|
-
* probe reading the times of the first few lines after its middle, passing over `skip`.
|
|
128
|
-
*/
|
|
129
104
|
async function seek(path, low, high, target, skip) {
|
|
130
105
|
return (await narrow(path, low, high, target, skip)).high;
|
|
131
106
|
}
|
|
132
|
-
/** seek's bisection: where it got, from both sides. */
|
|
133
107
|
async function narrow(path, low, high, target, skip) {
|
|
134
108
|
while (high - low > CHUNK_BYTES) {
|
|
135
109
|
let middle = Math.floor((low + high) / 2);
|
|
@@ -143,7 +117,7 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
143
117
|
}
|
|
144
118
|
const probe = await probeTime(path, middle, high, skip);
|
|
145
119
|
if (!probe)
|
|
146
|
-
break;
|
|
120
|
+
break;
|
|
147
121
|
if (probe.time >= target)
|
|
148
122
|
high = probe.start;
|
|
149
123
|
else
|
|
@@ -151,14 +125,13 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
151
125
|
}
|
|
152
126
|
return { low, high };
|
|
153
127
|
}
|
|
154
|
-
/** The first line starting after `from` (before `limit`), with the earliest time of the next few timed lines. */
|
|
155
128
|
async function probeTime(path, from, limit, skip) {
|
|
156
129
|
let start = -1;
|
|
157
130
|
let time = Infinity;
|
|
158
131
|
let timed = 0;
|
|
159
132
|
for await (const line of forward(path, from, Math.min(limit, from + PROBE_BYTES), skip)) {
|
|
160
133
|
if (line.start === from && from > 0)
|
|
161
|
-
continue;
|
|
134
|
+
continue;
|
|
162
135
|
if (line.start >= limit)
|
|
163
136
|
break;
|
|
164
137
|
if (start < 0)
|
|
@@ -171,25 +144,17 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
171
144
|
}
|
|
172
145
|
return start < 0 || timed === 0 ? null : { start, time };
|
|
173
146
|
}
|
|
174
|
-
/** The time of the first timed line from `from` on (a line start), if there's one in reach. */
|
|
175
147
|
async function timeAt(path, from, size, skip) {
|
|
176
148
|
for await (const line of forward(path, from, Math.min(size, from + PROBE_BYTES), skip))
|
|
177
149
|
if (line.time !== null)
|
|
178
150
|
return line.time;
|
|
179
151
|
return null;
|
|
180
152
|
}
|
|
181
|
-
/** Where the line holding byte `at` starts. */
|
|
182
153
|
async function lineStart(path, at) {
|
|
183
154
|
for await (const line of backward(path, at + 1))
|
|
184
155
|
return line.start;
|
|
185
156
|
return 0;
|
|
186
157
|
}
|
|
187
|
-
/**
|
|
188
|
-
* The stretches the backend wrote again (TranscriptLayout.copies): each starts at a line with the
|
|
189
|
-
* marker whose time goes back from the timed line before it, and runs until a line is newer than
|
|
190
|
-
* that one. Found by searching the whole file for the marker; the rest only
|
|
191
|
-
* reads around what's found.
|
|
192
|
-
*/
|
|
193
158
|
function copiesOf(path, size) {
|
|
194
159
|
if (!layout.copies)
|
|
195
160
|
return Promise.resolve([]);
|
|
@@ -199,7 +164,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
199
164
|
copies = findCopies(path, size, layout.copies);
|
|
200
165
|
copies.catch(() => searchedCopies.delete(key));
|
|
201
166
|
searchedCopies.set(key, copies);
|
|
202
|
-
// A few files' worth: a worker serves an agent's sessions.
|
|
203
167
|
if (searchedCopies.size > SEARCHED_FILES)
|
|
204
168
|
searchedCopies.delete(searchedCopies.keys().next().value);
|
|
205
169
|
}
|
|
@@ -209,7 +173,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
209
173
|
const needle = Buffer.from(marker);
|
|
210
174
|
const found = [];
|
|
211
175
|
for (let position = 0; position < size; position += SCAN_BYTES) {
|
|
212
|
-
// Overlapping by the marker's length, so one across two reads is found.
|
|
213
176
|
const from = Math.max(0, position - needle.length + 1);
|
|
214
177
|
const bytes = Buffer.from(await files.readFileRange(path, from, Math.min(size, position + SCAN_BYTES)));
|
|
215
178
|
for (let index = bytes.indexOf(needle); index >= 0; index = bytes.indexOf(needle, index + 1)) {
|
|
@@ -219,7 +182,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
219
182
|
}
|
|
220
183
|
const copies = [];
|
|
221
184
|
for (const [index, at] of found.entries()) {
|
|
222
|
-
// The marker's line, and the timed line before it.
|
|
223
185
|
const start = await lineStart(path, at);
|
|
224
186
|
let earlier = null;
|
|
225
187
|
for await (const before of backward(path, start)) {
|
|
@@ -235,13 +197,8 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
235
197
|
time = line.time;
|
|
236
198
|
break;
|
|
237
199
|
}
|
|
238
|
-
// A compaction as it happened comes after what's before it (compacting takes a while: 25s and
|
|
239
|
-
// more); a copy starts back at its time.
|
|
240
200
|
if (time === null || time >= earlier)
|
|
241
201
|
continue;
|
|
242
|
-
// It runs up to what was written before it, and ends with the first line newer than that. It
|
|
243
|
-
// holds what was said since a compaction, so it ends by the next marker: the rest of the file
|
|
244
|
-
// (other copies) can't mislead the search.
|
|
245
202
|
const next = found[index + 1];
|
|
246
203
|
const near = await narrow(path, start + 1, next === undefined ? size : await lineStart(path, next), earlier + 1, []);
|
|
247
204
|
let end = near.high;
|
|
@@ -255,17 +212,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
255
212
|
}
|
|
256
213
|
return copies;
|
|
257
214
|
}
|
|
258
|
-
/**
|
|
259
|
-
* The file's lines before `end`, last first, each with the time it's paged by: its own, unless it's
|
|
260
|
-
* odd, more than the slack away from both the timed lines around it in the same direction (a
|
|
261
|
-
* background task's result written minutes after it began, a note dated ahead), when it's the one
|
|
262
|
-
* before it's; a line without a time goes with the timed line after it. These times follow the file
|
|
263
|
-
* order to within the slack, so the late result is paged where it is in the conversation.
|
|
264
|
-
* `after`: the time of the first timed line from `end` on.
|
|
265
|
-
*/
|
|
266
215
|
async function* pagedBackward(path, end, after, skip) {
|
|
267
|
-
let next = after;
|
|
268
|
-
let waiting = [];
|
|
216
|
+
let next = after;
|
|
217
|
+
let waiting = [];
|
|
269
218
|
const settle = function* (before) {
|
|
270
219
|
const [timed, ...untimed] = waiting;
|
|
271
220
|
if (!timed)
|
|
@@ -282,7 +231,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
282
231
|
};
|
|
283
232
|
for await (const line of backward(path, end, skip)) {
|
|
284
233
|
if (line.time === null) {
|
|
285
|
-
// Before any timed line: it goes with the line after the end, or is the newest.
|
|
286
234
|
if (waiting.length === 0)
|
|
287
235
|
yield { ...line, time: next ?? Infinity };
|
|
288
236
|
else
|
|
@@ -302,11 +250,9 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
302
250
|
const copies = found?.copies ?? (await copiesOf(path, size));
|
|
303
251
|
const from = Math.min(found?.end ?? (before === null ? size : await seek(path, 0, size, before + TIME_SLACK_MS, copies)), size);
|
|
304
252
|
const after = found ? found.after : from < size ? await timeAt(path, from, size, copies) : null;
|
|
305
|
-
// Read back until the page is full and a line is older than its oldest by more than the slack:
|
|
306
|
-
// nothing before it can belong on the page.
|
|
307
253
|
const taken = [];
|
|
308
254
|
let count = 0;
|
|
309
|
-
let oldest = Infinity;
|
|
255
|
+
let oldest = Infinity;
|
|
310
256
|
let older = false;
|
|
311
257
|
for await (const line of pagedBackward(path, from, after, copies)) {
|
|
312
258
|
if (count >= limit && line.time < oldest - TIME_SLACK_MS) {
|
|
@@ -320,8 +266,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
320
266
|
if (count >= limit)
|
|
321
267
|
oldest = oldestOnPage(taken, limit);
|
|
322
268
|
}
|
|
323
|
-
// The page: its newest messages by time, ties with the oldest of them included. A line's messages
|
|
324
|
-
// stay together, so a page can hold a message or so more than the limit.
|
|
325
269
|
const kept = count >= limit ? taken.filter((line) => line.time >= oldest) : taken;
|
|
326
270
|
if (kept.length < taken.length)
|
|
327
271
|
older = true;
|
|
@@ -330,7 +274,6 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
330
274
|
nextBefore: older && Number.isFinite(oldest) ? new Date(oldest).toISOString() : null,
|
|
331
275
|
};
|
|
332
276
|
}
|
|
333
|
-
// Passing over the copies too: a resumed session's stretch written again isn't replayed twice.
|
|
334
277
|
async function replay(afterId, emit) {
|
|
335
278
|
const path = await locate();
|
|
336
279
|
if (!path)
|
|
@@ -361,9 +304,20 @@ export function createFileTranscript(files, locate, lineMessages, layout) {
|
|
|
361
304
|
}
|
|
362
305
|
return true;
|
|
363
306
|
}
|
|
364
|
-
|
|
307
|
+
async function find(match) {
|
|
308
|
+
const path = await locate();
|
|
309
|
+
if (!path)
|
|
310
|
+
return null;
|
|
311
|
+
const end = await files.size(path);
|
|
312
|
+
for await (const line of backward(path, end, await copiesOf(path, end))) {
|
|
313
|
+
const found = line.messages.find(match);
|
|
314
|
+
if (found)
|
|
315
|
+
return found;
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
return { page, replay, find };
|
|
365
320
|
}
|
|
366
|
-
/** The time of the `limit`-th newest message of `lines`. */
|
|
367
321
|
function oldestOnPage(lines, limit) {
|
|
368
322
|
const newestFirst = [...lines].sort((a, b) => b.time - a.time);
|
|
369
323
|
let count = 0;
|
|
@@ -386,7 +340,6 @@ function joined(first, second) {
|
|
|
386
340
|
}
|
|
387
341
|
const DEFAULT_PAGE_SIZE = 50;
|
|
388
342
|
const MAX_PAGE_SIZE = 500;
|
|
389
|
-
/** A page of the API's transcript (AgentTranscript.getTranscript); none stored for a session that never ran. */
|
|
390
343
|
export async function transcriptPage(transcript, { limit, before, cursor } = {}, found) {
|
|
391
344
|
const time = transcriptTime(before ?? cursor);
|
|
392
345
|
if (!transcript)
|
|
@@ -395,7 +348,6 @@ export async function transcriptPage(transcript, { limit, before, cursor } = {},
|
|
|
395
348
|
const page = await transcript.page(time, size, found);
|
|
396
349
|
return { ...page, nextCursor: page.nextBefore };
|
|
397
350
|
}
|
|
398
|
-
/** AgentTranscriptRequest.before as epoch ms; null for none. */
|
|
399
351
|
export function transcriptTime(before) {
|
|
400
352
|
if (before === undefined)
|
|
401
353
|
return null;
|
|
@@ -404,35 +356,27 @@ export function transcriptTime(before) {
|
|
|
404
356
|
throw new AgentInvalidError(`invalid time ${before}: give an ISO 8601 time`);
|
|
405
357
|
return time;
|
|
406
358
|
}
|
|
407
|
-
|
|
408
|
-
* The first file `depth` levels under `dir` whose name `matches` (the backends' own layouts, like
|
|
409
|
-
* projects/<project>/<id>.jsonl), each level listed at once; null when there's none, or no `dir`.
|
|
410
|
-
*/
|
|
411
|
-
async function findFile(files, dir, depth, matches) {
|
|
412
|
-
let names;
|
|
359
|
+
export async function directoryNames(files, dir) {
|
|
413
360
|
try {
|
|
414
|
-
|
|
361
|
+
return await files.listDirectory(dir);
|
|
415
362
|
}
|
|
416
363
|
catch (error) {
|
|
417
364
|
if (error instanceof SandboxNotFoundError)
|
|
418
365
|
return null;
|
|
419
366
|
throw error;
|
|
420
367
|
}
|
|
368
|
+
}
|
|
369
|
+
async function findFile(files, dir, depth, matches) {
|
|
370
|
+
const names = await directoryNames(files, dir);
|
|
371
|
+
if (!names)
|
|
372
|
+
return null;
|
|
421
373
|
if (depth <= 1) {
|
|
422
374
|
const name = names.find(matches);
|
|
423
375
|
return name === undefined ? null : `${dir}/${name}`;
|
|
424
376
|
}
|
|
425
|
-
|
|
426
|
-
const found = await Promise.all(names.sort().reverse().map((name) =>
|
|
427
|
-
// One that isn't a directory has nothing below it.
|
|
428
|
-
findFile(files, `${dir}/${name}`, depth - 1, matches).catch(() => null)));
|
|
377
|
+
const found = await Promise.all(names.sort().reverse().map((name) => findFile(files, `${dir}/${name}`, depth - 1, matches).catch(() => null)));
|
|
429
378
|
return found.find((path) => path !== null) ?? null;
|
|
430
379
|
}
|
|
431
|
-
/**
|
|
432
|
-
* `files` with what was already fetched of the file at `path` in the same round trip: its size, and
|
|
433
|
-
* pieces of it (what a page reads, mostly). Reading back beyond them (a page across huge tool
|
|
434
|
-
* outputs) fetches twice as much as the time before, so it takes a few more reads, not one per chunk.
|
|
435
|
-
*/
|
|
436
380
|
export function prefetchedFiles(files, path, size, pieces) {
|
|
437
381
|
let more = Math.max(CHUNK_BYTES, ...pieces.map(({ bytes }) => bytes.length));
|
|
438
382
|
return {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import manifest from "../vendor-types/manifest.json";
|
|
2
|
+
import type { AgentBackendInfo } from "../api.ts";
|
|
3
|
+
export declare function pinnedVersion(vendor: keyof typeof manifest, pkg: string, sourcePackage?: string): string;
|
|
4
|
+
export declare function installedPackage(installDir: string, pkg: string, version: string, executable: () => string): Promise<Omit<AgentBackendInfo, "backend">>;
|
|
5
|
+
export declare function installPackage(installDir: string, pkg: string, version: string, executable: () => string): Promise<void>;
|