@wardby/cli 0.7.0 → 0.9.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/.env.example +5 -5
- package/README.md +6 -1
- package/deploy/local/docker-compose.quickstart-coding.yml +11 -0
- package/dist/claude-coding-worker/driver.d.ts +12 -0
- package/dist/claude-coding-worker/driver.js +29 -7
- package/dist/claude-coding-worker/main.js +5 -1
- package/dist/claude-coding-worker/sdk.js +17 -1
- package/dist/claude-plugin/command.d.ts +64 -0
- package/dist/claude-plugin/command.js +379 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +2 -1
- package/dist/cli.js +71 -3
- package/dist/coding/code-host.d.ts +16 -0
- package/dist/coding/code-host.js +60 -0
- package/dist/coding/mcp-token.d.ts +12 -0
- package/dist/coding/mcp-token.js +26 -0
- package/dist/coding/protocol.js +2 -0
- package/dist/coding/redact.js +6 -1
- package/dist/coding/transcript/recorder.d.ts +5 -4
- package/dist/coding/transcript/recorder.js +3 -9
- package/dist/coding-worker/debug-trace.d.ts +3 -1
- package/dist/coding-worker/debug-trace.js +4 -2
- package/dist/coding-worker/driver.js +8 -1
- package/dist/coding-worker/main.js +5 -1
- package/dist/coding-worker/mcp-config.d.ts +27 -0
- package/dist/coding-worker/mcp-config.js +32 -0
- package/dist/coding-worker/sdk.d.ts +36 -0
- package/dist/coding-worker/sdk.js +28 -1
- package/dist/coding-worker/types.d.ts +4 -0
- package/dist/config/mcp-call-limit.d.ts +8 -0
- package/dist/config/mcp-call-limit.js +18 -0
- package/dist/config/mcp-servers.d.ts +8 -0
- package/dist/config/mcp-servers.js +12 -0
- package/dist/config/test-simulators.d.ts +10 -0
- package/dist/config/test-simulators.js +28 -0
- package/dist/config/tool-timeout.d.ts +1 -0
- package/dist/config/tool-timeout.js +18 -0
- package/dist/core/coding-mcp.d.ts +36 -0
- package/dist/core/coding-mcp.js +253 -0
- package/dist/core/coding-repository.d.ts +46 -0
- package/dist/core/coding-repository.js +92 -0
- package/dist/core/delegation-slots.d.ts +27 -0
- package/dist/core/delegation-slots.js +44 -0
- package/dist/core/dispatch.d.ts +6 -2
- package/dist/core/dispatch.js +39 -11
- package/dist/core/engine-native.d.ts +2 -0
- package/dist/core/engine-native.js +13 -0
- package/dist/core/error-code.js +2 -0
- package/dist/core/grants.d.ts +28 -3
- package/dist/core/grants.js +46 -4
- package/dist/core/host-events.js +7 -3
- package/dist/core/host-status.js +2 -2
- package/dist/core/issue-status.js +4 -3
- package/dist/core/listen-address.d.ts +10 -0
- package/dist/core/listen-address.js +14 -0
- package/dist/core/mark-ready.d.ts +1 -1
- package/dist/core/mark-ready.js +1 -1
- package/dist/core/mcp-client/client.d.ts +47 -0
- package/dist/core/mcp-client/client.js +141 -0
- package/dist/core/mcp-client/jsonrpc.d.ts +15 -0
- package/dist/core/mcp-client/jsonrpc.js +54 -0
- package/dist/core/mcp-client/results.d.ts +13 -0
- package/dist/core/mcp-client/results.js +42 -0
- package/dist/core/mcp-servers.d.ts +90 -0
- package/dist/core/mcp-servers.js +230 -0
- package/dist/core/mcp-tools.d.ts +108 -0
- package/dist/core/mcp-tools.js +287 -0
- package/dist/core/merge-order-check.js +38 -19
- package/dist/core/notification-dispatcher.js +2 -1
- package/dist/core/power-idle.d.ts +8 -2
- package/dist/core/power-idle.js +17 -3
- package/dist/core/power.d.ts +5 -0
- package/dist/core/power.js +5 -0
- package/dist/core/related-pull-requests.js +26 -10
- package/dist/core/retention-days.d.ts +5 -0
- package/dist/core/retention-days.js +14 -0
- package/dist/core/review-fix.js +2 -2
- package/dist/core/review-host-tools.js +3 -1
- package/dist/core/run-steps/config.d.ts +25 -0
- package/dist/core/run-steps/config.js +40 -0
- package/dist/core/run-steps/control-chars.d.ts +16 -0
- package/dist/core/run-steps/control-chars.js +26 -0
- package/dist/core/run-steps/detail.d.ts +32 -0
- package/dist/core/run-steps/detail.js +240 -0
- package/dist/core/run-steps/extract.d.ts +52 -0
- package/dist/core/run-steps/extract.js +467 -0
- package/dist/core/run-steps/ingress.d.ts +51 -0
- package/dist/core/run-steps/ingress.js +160 -0
- package/dist/core/run-steps/last-step.d.ts +15 -0
- package/dist/core/run-steps/last-step.js +35 -0
- package/dist/core/run-steps/native.d.ts +48 -0
- package/dist/core/run-steps/native.js +164 -0
- package/dist/core/run-steps/seen.d.ts +16 -0
- package/dist/core/run-steps/seen.js +35 -0
- package/dist/core/run-steps/summarize.d.ts +57 -0
- package/dist/core/run-steps/summarize.js +304 -0
- package/dist/core/run-steps/sweep.d.ts +21 -0
- package/dist/core/run-steps/sweep.js +41 -0
- package/dist/core/run-steps/types.d.ts +89 -0
- package/dist/core/run-steps/types.js +39 -0
- package/dist/core/run-steps/wire.d.ts +35 -0
- package/dist/core/run-steps/wire.js +47 -0
- package/dist/core/run-steps/writer.d.ts +49 -0
- package/dist/core/run-steps/writer.js +279 -0
- package/dist/core/runner.d.ts +70 -16
- package/dist/core/runner.js +296 -74
- package/dist/core/secret-broker-config.d.ts +2 -0
- package/dist/core/secret-broker-config.js +1 -1
- package/dist/core/secret-guard.d.ts +5 -2
- package/dist/core/secret-guard.js +22 -7
- package/dist/core/secrets.d.ts +11 -1
- package/dist/core/secrets.js +27 -1
- package/dist/core/serializable-retry.d.ts +18 -0
- package/dist/core/serializable-retry.js +43 -0
- package/dist/core/tool-admin.d.ts +5 -1
- package/dist/core/tool-admin.js +7 -2
- package/dist/core/tool-names.d.ts +13 -0
- package/dist/core/tool-names.js +20 -0
- package/dist/core/webhooks.d.ts +4 -0
- package/dist/core/webhooks.js +68 -49
- package/dist/core/workflow-run-events.js +2 -1
- package/dist/generated/prisma/browser.d.ts +39 -0
- package/dist/generated/prisma/client.d.ts +39 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +80 -50
- package/dist/generated/prisma/enums.d.ts +6 -0
- package/dist/generated/prisma/enums.js +5 -0
- package/dist/generated/prisma/internal/class.d.ts +77 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +632 -1
- package/dist/generated/prisma/internal/prismaNamespace.js +94 -3
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +98 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +94 -3
- package/dist/generated/prisma/models/Agent.d.ts +372 -1
- package/dist/generated/prisma/models/AgentMcpServer.d.ts +1412 -0
- package/dist/generated/prisma/models/AgentMcpServer.js +1 -0
- package/dist/generated/prisma/models/AgentRepository.d.ts +40 -1
- package/dist/generated/prisma/models/AuthUser.d.ts +1 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +0 -7
- package/dist/generated/prisma/models/CodingProxySession.d.ts +159 -2
- package/dist/generated/prisma/models/CodingRun.d.ts +76 -1
- package/dist/generated/prisma/models/HostProvider.d.ts +2176 -0
- package/dist/generated/prisma/models/HostProvider.js +1 -0
- package/dist/generated/prisma/models/HostProviderCredential.d.ts +1285 -0
- package/dist/generated/prisma/models/HostProviderCredential.js +1 -0
- package/dist/generated/prisma/models/HostProviderOperation.d.ts +1470 -0
- package/dist/generated/prisma/models/HostProviderOperation.js +1 -0
- package/dist/generated/prisma/models/HostProviderTrustedAccount.d.ts +1145 -0
- package/dist/generated/prisma/models/HostProviderTrustedAccount.js +1 -0
- package/dist/generated/prisma/models/McpServer.d.ts +1500 -0
- package/dist/generated/prisma/models/McpServer.js +1 -0
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
- package/dist/generated/prisma/models/Principal.d.ts +167 -0
- package/dist/generated/prisma/models/ResourceGrant.d.ts +1 -1
- package/dist/generated/prisma/models/Run.d.ts +503 -1
- package/dist/generated/prisma/models/RunStep.d.ts +1453 -0
- package/dist/generated/prisma/models/RunStep.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +387 -0
- package/dist/generated/prisma/models/Tool.d.ts +223 -1
- package/dist/generated/prisma/models.d.ts +7 -0
- package/dist/help/search.js +12 -3
- package/dist/help-index.json +812 -52
- package/dist/import/create.js +16 -1
- package/dist/import/neutral-schema.d.ts +1 -0
- package/dist/import/neutral-schema.js +2 -0
- package/dist/mcp/auth/access.d.ts +1 -0
- package/dist/mcp/auth/grants-cli.d.ts +6 -4
- package/dist/mcp/auth/grants-cli.js +42 -3
- package/dist/mcp/auth/resource-server.d.ts +3 -1
- package/dist/mcp/auth/resource-server.js +17 -2
- package/dist/mcp/context.d.ts +6 -0
- package/dist/mcp/index.js +21 -0
- package/dist/mcp/tools/agents.js +135 -20
- package/dist/mcp/tools/grants.js +66 -28
- package/dist/mcp/tools/host-providers.d.ts +2 -0
- package/dist/mcp/tools/host-providers.js +215 -0
- package/dist/mcp/tools/mcp-servers.d.ts +26 -0
- package/dist/mcp/tools/mcp-servers.js +481 -0
- package/dist/mcp/tools/power.js +2 -2
- package/dist/mcp/tools/repositories.js +50 -10
- package/dist/mcp/tools/run-access.d.ts +7 -0
- package/dist/mcp/tools/run-access.js +14 -0
- package/dist/mcp/tools/run-steps.d.ts +16 -0
- package/dist/mcp/tools/run-steps.js +85 -0
- package/dist/mcp/tools/runs.js +186 -18
- package/dist/mcp/tools/secret-elicitation.d.ts +2 -0
- package/dist/mcp/tools/secret-elicitation.js +25 -2
- package/dist/mcp/tools/secrets.js +38 -4
- package/dist/mcp/tools/tools.d.ts +6 -4
- package/dist/mcp/tools/tools.js +40 -8
- package/dist/mcp/tools/trigger.js +28 -6
- package/dist/mcp/transport/http-limits.d.ts +2 -0
- package/dist/mcp/transport/http-limits.js +6 -2
- package/dist/mcp/webhooks/ingress.js +10 -0
- package/dist/native-worker/gateway-server.d.ts +18 -1
- package/dist/native-worker/gateway-server.js +38 -9
- package/dist/native-worker/gateway.d.ts +5 -0
- package/dist/native-worker/gateway.js +13 -1
- package/dist/native-worker/http-server.d.ts +6 -4
- package/dist/native-worker/http-server.js +53 -8
- package/dist/native-worker/ledger.d.ts +6 -2
- package/dist/native-worker/ledger.js +5 -4
- package/dist/native-worker/protocol.d.ts +1 -0
- package/dist/native-worker/protocol.js +4 -1
- package/dist/providers/coding-proxy/capability-hash.d.ts +2 -0
- package/dist/providers/coding-proxy/capability-hash.js +5 -0
- package/dist/providers/coding-proxy/mcp-route.d.ts +34 -0
- package/dist/providers/coding-proxy/mcp-route.js +166 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +2 -0
- package/dist/providers/coding-proxy/memory-ledger.js +16 -0
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +1 -0
- package/dist/providers/coding-proxy/prisma-ledger.js +36 -2
- package/dist/providers/coding-proxy/proxy.d.ts +33 -1
- package/dist/providers/coding-proxy/proxy.js +266 -75
- package/dist/providers/coding-proxy/run-step-forwarder.d.ts +42 -0
- package/dist/providers/coding-proxy/run-step-forwarder.js +206 -0
- package/dist/providers/coding-proxy/runtime.d.ts +13 -0
- package/dist/providers/coding-proxy/runtime.js +87 -4
- package/dist/providers/coding-proxy/server.d.ts +3 -0
- package/dist/providers/coding-proxy/server.js +10 -0
- package/dist/providers/coding-proxy/types.d.ts +18 -0
- package/dist/providers/engine/types.d.ts +26 -0
- package/dist/providers/executor/composition.js +5 -0
- package/dist/providers/executor/container.d.ts +47 -1
- package/dist/providers/executor/container.js +84 -8
- package/dist/providers/host-tools/invoke.d.ts +37 -0
- package/dist/providers/host-tools/invoke.js +117 -0
- package/dist/providers/host-tools/operations.d.ts +65 -0
- package/dist/providers/host-tools/operations.js +149 -0
- package/dist/providers/host-tools/registry.d.ts +79 -0
- package/dist/providers/host-tools/registry.js +362 -0
- package/dist/providers/host-tools/request-guard.d.ts +17 -0
- package/dist/providers/host-tools/request-guard.js +99 -0
- package/dist/providers/host-tools/self-test.d.ts +64 -0
- package/dist/providers/host-tools/self-test.js +142 -0
- package/dist/providers/jobs/docker-isolation.d.ts +2 -2
- package/dist/providers/jobs/docker-isolation.js +30 -8
- package/dist/providers/jobs/docker.d.ts +8 -0
- package/dist/providers/jobs/docker.js +33 -9
- package/dist/providers/jobs/kubernetes-isolation.d.ts +3 -1
- package/dist/providers/jobs/kubernetes-isolation.js +15 -2
- package/dist/providers/jobs/kubernetes.d.ts +13 -0
- package/dist/providers/jobs/kubernetes.js +28 -5
- package/dist/providers/jobs/types.d.ts +6 -0
- package/dist/providers/review-host/types.d.ts +6 -4
- package/dist/providers/review-host/types.js +1 -1
- package/dist/providers/vcs/git.d.ts +6 -2
- package/dist/providers/vcs/git.js +15 -4
- package/dist/providers/vcs/github.d.ts +2 -71
- package/dist/providers/vcs/github.js +8 -11
- package/dist/providers/vcs/index.d.ts +1 -1
- package/dist/providers/vcs/index.js +1 -1
- package/dist/providers/vcs/remote.d.ts +4 -0
- package/dist/providers/vcs/remote.js +7 -1
- package/dist/providers/vcs/routing.d.ts +12 -6
- package/dist/providers/vcs/routing.js +21 -6
- package/dist/providers/vcs/types.d.ts +71 -3
- package/dist/quickstart/index.d.ts +5 -0
- package/dist/quickstart/index.js +21 -0
- package/dist/quickstart-images.json +1 -1
- package/dist/sandbox/eval-core.d.ts +12 -2
- package/dist/sandbox/eval-core.js +20 -4
- package/dist/sandbox/host-functions.d.ts +4 -0
- package/dist/sandbox/host-functions.js +7 -2
- package/dist/sandbox/limits.d.ts +4 -1
- package/dist/sandbox/limits.js +4 -1
- package/dist/sandbox/run-in-sandbox.d.ts +6 -0
- package/dist/sandbox/run-in-sandbox.js +14 -2
- package/dist/sandbox/safe-fetch.d.ts +2 -0
- package/dist/sandbox/safe-fetch.js +1 -1
- package/dist/sandbox/secret-broker.d.ts +1 -0
- package/dist/sandbox/secret-broker.js +1 -1
- package/dist/sandbox/tool-timeout.d.ts +32 -0
- package/dist/sandbox/tool-timeout.js +52 -0
- package/dist/sandbox/user-tool.d.ts +8 -1
- package/dist/sandbox/user-tool.js +9 -3
- package/dist/serve.js +26 -18
- package/dist/viewer/api-schema.d.ts +66 -0
- package/dist/viewer/api-schema.js +31 -0
- package/dist/viewer/graph.js +2 -1
- package/dist/viewer/openapi.js +2 -1
- package/dist/viewer/run-detail.d.ts +2 -0
- package/dist/viewer/run-detail.js +26 -1
- package/dist/wardby-bin.js +5 -0
- package/docs/README.md +11 -1
- package/docs/agent-recipes.md +37 -4
- package/docs/architecture-runtime.md +1 -1
- package/docs/claude-code-plugin.md +208 -0
- package/docs/code-review-agents.md +6 -0
- package/docs/coding-agent-setup.md +94 -1
- package/docs/coding-worker-byo-images.md +4 -2
- package/docs/coding-worker-isolation.md +94 -7
- package/docs/debugging-agent-runs.md +354 -0
- package/docs/getting-started-gke.md +33 -11
- package/docs/getting-started-identity-provider.md +43 -37
- package/docs/getting-started.md +8 -0
- package/docs/host-providers.md +294 -0
- package/docs/mcp-servers.md +263 -0
- package/docs/native-sandbox.md +31 -9
- package/docs/security-deployment.md +161 -31
- package/docs/tool-secrets.md +3 -0
- package/docs/viewer-api.md +27 -12
- package/docs/viewer-api.openapi.yml +78 -2
- package/help/admin-viewer.md +5 -0
- package/help/agent-recipes.md +33 -2
- package/help/brokered-secrets.md +3 -0
- package/help/build-claude-code-image.md +1 -1
- package/help/claude-code-run-pane.md +63 -0
- package/help/deploy-gke.md +5 -0
- package/help/errors/coding-mcp-gateway-unavailable.md +46 -0
- package/help/errors/coding-mcp-pins-unavailable.md +35 -0
- package/help/errors/database-auth-invalid.md +1 -1
- package/help/errors/host-provider-error.md +40 -0
- package/help/errors/host-tool-failed.md +36 -0
- package/help/errors/mcp-call-limit.md +22 -0
- package/help/errors/mcp-call-timeout.md +22 -0
- package/help/errors/mcp-server-auth-failed.md +22 -0
- package/help/errors/mcp-server-credentials-unavailable.md +45 -0
- package/help/errors/mcp-server-error.md +28 -0
- package/help/errors/mcp-server-unreachable.md +22 -0
- package/help/errors/mcp-servers-off.md +21 -0
- package/help/errors/mcp-tool-not-allowed.md +26 -0
- package/help/errors/mcp-tool-removed.md +22 -0
- package/help/errors/mcp-unavailable.md +25 -0
- package/help/errors/native-sandbox-capacity.md +1 -1
- package/help/errors/native-sandbox-deadline-exceeded.md +1 -1
- package/help/errors/native-sandbox-docker-failed.md +1 -1
- package/help/errors/native-sandbox-gateway-error.md +1 -1
- package/help/errors/native-sandbox-gateway-unavailable.md +1 -1
- package/help/errors/native-sandbox-image-not-pinned.md +1 -1
- package/help/errors/native-sandbox-isolation-mismatch.md +1 -1
- package/help/errors/native-sandbox-network-unenforced.md +1 -1
- package/help/errors/native-sandbox-requires-catalog.md +1 -1
- package/help/errors/native-sandbox-unavailable.md +1 -1
- package/help/errors/native-sandbox-warm-delivery-failed.md +1 -1
- package/help/errors/native-sandbox-worker-exited.md +1 -1
- package/help/errors/native-sandbox-worker-lost.md +1 -1
- package/help/errors/native-sandbox-worker-unready.md +1 -1
- package/help/errors/repository-not-listed.md +36 -0
- package/help/errors/repository-required.md +36 -0
- package/help/errors/tool-timeout.md +38 -0
- package/help/host-providers.md +40 -0
- package/help/identity-and-access.md +4 -1
- package/help/low-power-mode.md +19 -8
- package/help/mcp-servers.md +73 -0
- package/help/mcp.md +9 -2
- package/help/native-capabilities.md +27 -1
- package/help/native-sandbox.md +1 -1
- package/help/operating-agents.md +16 -0
- package/help/related-pull-requests.md +7 -3
- package/help/repo-instructions-and-skills.md +3 -1
- package/help/resume-runs-locally.md +7 -0
- package/help/run-steps.md +140 -0
- package/help/stop-run.md +1 -1
- package/help/troubleshooting/coding-workers.md +9 -1
- package/help/troubleshooting/debugging-agent-runs.md +29 -0
- package/package.json +2 -1
- package/prisma/migrations/20261102000000_host_providers/migration.sql +56 -0
- package/prisma/migrations/20261104000000_coding_agent_repository_list/migration.sql +5 -0
- package/prisma/migrations/20261106000000_tool_timeout/migration.sql +4 -0
- package/prisma/migrations/20261107000000_mcp_servers/migration.sql +33 -0
- package/prisma/migrations/20261108000000_coding_mcp/migration.sql +5 -0
- package/prisma/migrations/20261109000000_task_run_index/migration.sql +3 -0
- package/prisma/migrations/20261110000000_run_steps/migration.sql +26 -0
- package/prisma/migrations/20261111000000_run_steps_viewer_notify/migration.sql +59 -0
- package/prisma/migrations/20261112000000_run_steps_detail/migration.sql +9 -0
- package/prisma/schema.prisma +211 -14
- package/scripts/git-askpass.sh +1 -1
package/dist/core/review-fix.js
CHANGED
|
@@ -182,7 +182,7 @@ export async function startReviewFixAfterReview(runId, deps) {
|
|
|
182
182
|
const check = await deps.db.runHostCheck.findUnique({ where: { runId } });
|
|
183
183
|
if (!check || check.verdict !== "CHANGES_REQUESTED" || check.prNumber === null || !check.reviewBody)
|
|
184
184
|
return;
|
|
185
|
-
if (check.provider
|
|
185
|
+
if (check.provider === "local")
|
|
186
186
|
return;
|
|
187
187
|
const result = await startReviewFixRound({
|
|
188
188
|
provider: check.provider,
|
|
@@ -256,7 +256,7 @@ async function reReview(runId, deps) {
|
|
|
256
256
|
if (root.parentRunId)
|
|
257
257
|
return skip("not_fix_round");
|
|
258
258
|
const status = root.hostStatus;
|
|
259
|
-
if (!status || status.provider
|
|
259
|
+
if (!status || status.provider === "local")
|
|
260
260
|
return skip("not_fix_round");
|
|
261
261
|
const provider = status.provider;
|
|
262
262
|
const { repository, number: prNumber } = status;
|
|
@@ -14,6 +14,7 @@ import { MAX_PATCH_CURSOR_CHARS } from "../providers/review-host/patch-pages.js"
|
|
|
14
14
|
import { escapeHtmlComments } from "../providers/review-host/review-format.js";
|
|
15
15
|
import { REVIEW_HOST_PROVIDERS, PatchCursorError, ReviewHostError, } from "../providers/review-host/types.js";
|
|
16
16
|
import { isLocalRepository, normalizeGitHubRepository, normalizeLocalRepository } from "../coding/protocol.js";
|
|
17
|
+
import { codeProviderOf, normalizeHostedRepository } from "../coding/code-host.js";
|
|
17
18
|
import { ciForAgent } from "./ci-context.js";
|
|
18
19
|
import { logger } from "./logger.js";
|
|
19
20
|
import { collectRelatedPullRequests } from "./related-pull-requests.js";
|
|
@@ -221,11 +222,12 @@ function normalizeFor(provider, value) {
|
|
|
221
222
|
return normalizeGitHubRepository(value);
|
|
222
223
|
if (provider === "local")
|
|
223
224
|
return normalizeLocalRepository(value);
|
|
225
|
+
const repository = normalizeHostedRepository(value);
|
|
226
|
+
return codeProviderOf(repository) === provider ? repository : null;
|
|
224
227
|
}
|
|
225
228
|
catch {
|
|
226
229
|
return null;
|
|
227
230
|
}
|
|
228
|
-
return null;
|
|
229
231
|
}
|
|
230
232
|
export function resolveLink(links, repositoryArg) {
|
|
231
233
|
const raw = repositoryArg.trim();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run steps settings, read at start-up by every process that records or serves steps (the server,
|
|
3
|
+
* `wardby scheduler`, the native gateway). An invalid value stops start-up, naming the variable.
|
|
4
|
+
*/
|
|
5
|
+
export type RunStepsLevel = "off" | "summary" | "detail";
|
|
6
|
+
export declare const RUN_STEPS_LEVELS: readonly RunStepsLevel[];
|
|
7
|
+
/** WARDBY_RUN_STEPS: the instance's ceiling. Default summary. */
|
|
8
|
+
export declare function loadRunStepsLevel(env?: NodeJS.ProcessEnv): RunStepsLevel;
|
|
9
|
+
/** A run's level: min(the instance's ceiling, the agent's setting); an unset agent is at summary. */
|
|
10
|
+
export declare function runStepsLevelFor(ceiling: RunStepsLevel, agentSetting: RunStepsLevel | null | undefined): RunStepsLevel;
|
|
11
|
+
/**
|
|
12
|
+
* The level a run records: the one fixed at dispatch, never above this process's current ceiling
|
|
13
|
+
* (lowering the ceiling stops detail for in-flight runs too). A run from before the field is at
|
|
14
|
+
* most summary.
|
|
15
|
+
*/
|
|
16
|
+
export declare function recordedRunStepsLevel(runLevel: RunStepsLevel | null | undefined, ceiling: RunStepsLevel): RunStepsLevel;
|
|
17
|
+
/** The level to fix on a run being created for `agent` (dispatch, createRun, delegation). */
|
|
18
|
+
export declare function dispatchRunStepsLevel(agent: {
|
|
19
|
+
runSteps: RunStepsLevel | null;
|
|
20
|
+
}, env?: NodeJS.ProcessEnv): RunStepsLevel;
|
|
21
|
+
/** update_agent / get_agent: the agent asks for more than the instance records (not a refusal). */
|
|
22
|
+
export declare function runStepsAboveCeilingWarning(agentSetting: RunStepsLevel | null | undefined, ceiling: RunStepsLevel): string | undefined;
|
|
23
|
+
export declare const DEFAULT_RUN_STEP_RETENTION_DAYS = 30;
|
|
24
|
+
/** RUN_STEP_RETENTION_DAYS: days a step is kept after it is written. Applies to steps written after a change. */
|
|
25
|
+
export declare function loadRunStepRetentionDays(env?: NodeJS.ProcessEnv): number;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { loadRetentionDays } from "../retention-days.js";
|
|
2
|
+
export const RUN_STEPS_LEVELS = ["off", "summary", "detail"];
|
|
3
|
+
const RANK = { off: 0, summary: 1, detail: 2 };
|
|
4
|
+
/** WARDBY_RUN_STEPS: the instance's ceiling. Default summary. */
|
|
5
|
+
export function loadRunStepsLevel(env = process.env) {
|
|
6
|
+
const raw = env.WARDBY_RUN_STEPS?.trim();
|
|
7
|
+
if (!raw)
|
|
8
|
+
return "summary";
|
|
9
|
+
if (!RUN_STEPS_LEVELS.includes(raw))
|
|
10
|
+
throw new Error("WARDBY_RUN_STEPS must be off, summary or detail.");
|
|
11
|
+
return raw;
|
|
12
|
+
}
|
|
13
|
+
/** A run's level: min(the instance's ceiling, the agent's setting); an unset agent is at summary. */
|
|
14
|
+
export function runStepsLevelFor(ceiling, agentSetting) {
|
|
15
|
+
const asked = agentSetting ?? "summary";
|
|
16
|
+
return RANK[asked] <= RANK[ceiling] ? asked : ceiling;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The level a run records: the one fixed at dispatch, never above this process's current ceiling
|
|
20
|
+
* (lowering the ceiling stops detail for in-flight runs too). A run from before the field is at
|
|
21
|
+
* most summary.
|
|
22
|
+
*/
|
|
23
|
+
export function recordedRunStepsLevel(runLevel, ceiling) {
|
|
24
|
+
return runStepsLevelFor(ceiling, runLevel);
|
|
25
|
+
}
|
|
26
|
+
/** The level to fix on a run being created for `agent` (dispatch, createRun, delegation). */
|
|
27
|
+
export function dispatchRunStepsLevel(agent, env = process.env) {
|
|
28
|
+
return runStepsLevelFor(loadRunStepsLevel(env), agent.runSteps);
|
|
29
|
+
}
|
|
30
|
+
/** update_agent / get_agent: the agent asks for more than the instance records (not a refusal). */
|
|
31
|
+
export function runStepsAboveCeilingWarning(agentSetting, ceiling) {
|
|
32
|
+
if (!agentSetting || RANK[agentSetting] <= RANK[ceiling])
|
|
33
|
+
return undefined;
|
|
34
|
+
return `runSteps is ${agentSetting} but this instance allows up to ${ceiling} (WARDBY_RUN_STEPS), so its runs record ${ceiling}. See the run-steps help article.`;
|
|
35
|
+
}
|
|
36
|
+
export const DEFAULT_RUN_STEP_RETENTION_DAYS = 30;
|
|
37
|
+
/** RUN_STEP_RETENTION_DAYS: days a step is kept after it is written. Applies to steps written after a change. */
|
|
38
|
+
export function loadRunStepRetentionDays(env = process.env) {
|
|
39
|
+
return loadRetentionDays(env, "RUN_STEP_RETENTION_DAYS", DEFAULT_RUN_STEP_RETENTION_DAYS);
|
|
40
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step text as plain text: tool output and input are untrusted (repository content, command
|
|
3
|
+
* output), and a reader may show them in a terminal. Whole ANSI escape sequences are removed (CSI
|
|
4
|
+
* such as colour codes; OSC, DCS, SOS, PM and APC strings ended by BEL or ST, such as OSC 8 links
|
|
5
|
+
* and OSC 52 clipboard writes), then every other C0 and C1 control character except `\n` and `\t`.
|
|
6
|
+
* Only a well-formed sequence is removed whole: a bare or malformed ESC (or C1 byte) is removed
|
|
7
|
+
* alone and never takes a printable character after it (`ESC Z` leaves `Z`), so it cannot eat
|
|
8
|
+
* the first character of a secret value. A well-formed CSI can still end in a letter (`ESC [ Z`),
|
|
9
|
+
* which is why the writer masks secret values on the raw text before this runs.
|
|
10
|
+
* `\r\n` becomes `\n`; a lone `\r` is dropped. Removing characters can only join text, never split
|
|
11
|
+
* it, so a secret split by colour codes is whole again for redaction, which runs after this.
|
|
12
|
+
*
|
|
13
|
+
* No imports: dependency-free, so any reader of step text can share it.
|
|
14
|
+
*/
|
|
15
|
+
/** `text` without terminal control sequences or control characters other than `\n` and `\t`. */
|
|
16
|
+
export declare function stripControlSequences(text: string): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step text as plain text: tool output and input are untrusted (repository content, command
|
|
3
|
+
* output), and a reader may show them in a terminal. Whole ANSI escape sequences are removed (CSI
|
|
4
|
+
* such as colour codes; OSC, DCS, SOS, PM and APC strings ended by BEL or ST, such as OSC 8 links
|
|
5
|
+
* and OSC 52 clipboard writes), then every other C0 and C1 control character except `\n` and `\t`.
|
|
6
|
+
* Only a well-formed sequence is removed whole: a bare or malformed ESC (or C1 byte) is removed
|
|
7
|
+
* alone and never takes a printable character after it (`ESC Z` leaves `Z`), so it cannot eat
|
|
8
|
+
* the first character of a secret value. A well-formed CSI can still end in a letter (`ESC [ Z`),
|
|
9
|
+
* which is why the writer masks secret values on the raw text before this runs.
|
|
10
|
+
* `\r\n` becomes `\n`; a lone `\r` is dropped. Removing characters can only join text, never split
|
|
11
|
+
* it, so a secret split by colour codes is whole again for redaction, which runs after this.
|
|
12
|
+
*
|
|
13
|
+
* No imports: dependency-free, so any reader of step text can share it.
|
|
14
|
+
*/
|
|
15
|
+
/* eslint-disable no-control-regex -- matching control characters is this file's purpose */
|
|
16
|
+
/** OSC, DCS, SOS, PM, APC (7-bit or C1 introducer), up to BEL or ST (ESC \ or C1 ST). */
|
|
17
|
+
const STRING_SEQUENCE = /(?:\x1b[\]PX^_]|[\x90\x98\x9d\x9e\x9f])[^\x07\x1b\x9c]*(?:\x07|\x1b\\|\x9c)/g;
|
|
18
|
+
/** CSI (7-bit or C1): parameter bytes, intermediate bytes, one final byte. */
|
|
19
|
+
const CSI_SEQUENCE = /(?:\x1b\[|\x9b)[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g;
|
|
20
|
+
/** C0 except \t and \n (\r included), DEL, and C1. */
|
|
21
|
+
const CONTROL = /[\x00-\x08\x0b-\x1f\x7f-\x9f]/g;
|
|
22
|
+
/* eslint-enable no-control-regex */
|
|
23
|
+
/** `text` without terminal control sequences or control characters other than `\n` and `\t`. */
|
|
24
|
+
export function stripControlSequences(text) {
|
|
25
|
+
return text.replace(STRING_SEQUENCE, "").replace(CSI_SEQUENCE, "").replace(/\r\n/g, "\n").replace(CONTROL, "");
|
|
26
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ExtractedResult, type ExtractedStep } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `text` collapsed as summaries are (collapseWhitespace: runs of whitespace become one space,
|
|
4
|
+
* trimmed), with each collapsed character's [from, to) span in `text`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function collapseWithMap(text: string): {
|
|
7
|
+
collapsed: string;
|
|
8
|
+
from: number[];
|
|
9
|
+
to: number[];
|
|
10
|
+
};
|
|
11
|
+
/** The most a cut head's partial first line drop takes (afterCutHead). */
|
|
12
|
+
export declare const CUT_HEAD_DROP_CHARS = 256;
|
|
13
|
+
/** A tool step's stored detail with its output appended, within MAX_STEP_DETAIL_CHARS. */
|
|
14
|
+
export declare function joinDetail(existing: string | null, suffix: string): string;
|
|
15
|
+
export interface StepDetailer {
|
|
16
|
+
/**
|
|
17
|
+
* `raw` (untrusted text before control sequences are stripped) with every form of every secret
|
|
18
|
+
* value, the secret start it ends in, the secret end it starts with when its head was cut, and
|
|
19
|
+
* both at every line and ellipsis boundary, each replaced by `marker`: so a stripped escape
|
|
20
|
+
* sequence cannot take a character of a secret, whole or partial, and hide the rest of it.
|
|
21
|
+
*/
|
|
22
|
+
premask(raw: string, headWasCut: boolean, marker: string): string;
|
|
23
|
+
/** A step's detail: a tool's input (or its summary text when no input was sent), or a said step's text. */
|
|
24
|
+
step(step: ExtractedStep): string;
|
|
25
|
+
/** The text appended to a tool step's detail when its result arrives: the heading and the output's redacted end. */
|
|
26
|
+
output(result: Required<Pick<ExtractedResult, "output">> & Pick<ExtractedResult, "outputCut">): string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Detail texts for one batch, against every secret value delivered to the run (the agent's and the
|
|
30
|
+
* run's own). The forms, and each form's KMP table for the edge checks, are built once per batch.
|
|
31
|
+
*/
|
|
32
|
+
export declare function stepDetailer(secretValues: readonly string[]): StepDetailer;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The detail level's text (RunStep.detail): a tool's input, the end of its output, a model
|
|
3
|
+
* message. Redacted on the control plane, on the raw text, before any cut, against the same values
|
|
4
|
+
* and forms as summaries (stepSummarizer): every form of every secret value (secretForms), matched
|
|
5
|
+
* both in the text as written and in its whitespace-collapsed form (mapped back, so a secret the
|
|
6
|
+
* model wrote with other spacing is masked while the text keeps its lines), the longest secret
|
|
7
|
+
* start the text ends in (and, for an output whose head was cut, the longest secret end it starts
|
|
8
|
+
* with), the same two checks at every line break and ellipsis inside it (an agent may elide an
|
|
9
|
+
* output's middle, splitting a secret around its marker), then token shapes (redactSecrets). Only
|
|
10
|
+
* then is it cut.
|
|
11
|
+
*/
|
|
12
|
+
import { REDACTED, redactSecrets } from "../../coding/redact.js";
|
|
13
|
+
import { MIN_REDACTABLE_SECRET_LENGTH, maskSpans, mergeSpans, secretSpans } from "../secret-spans.js";
|
|
14
|
+
import { secretForms, secretTail } from "./summarize.js";
|
|
15
|
+
import { DETAIL_INPUT_CHARS, DETAIL_OUTPUT_CHARS, DETAIL_OUTPUT_HEADING, DETAIL_SAID_CHARS, MAX_STEP_DETAIL_CHARS, MAX_STEP_TEXT_CHARS, tailOf, } from "./types.js";
|
|
16
|
+
const WS = /\s/;
|
|
17
|
+
// A PEM private key's lone edges: complete pairs are masked by redactSecrets first, so what
|
|
18
|
+
// matches here is a BEGIN whose END is not in the text, or an END whose BEGIN was cut away.
|
|
19
|
+
const PEM_BEGIN_TO_END = /-----BEGIN (?:[A-Z ]{1,32} )?PRIVATE KEY-----[\s\S]*$/;
|
|
20
|
+
const PEM_START_TO_END = /^[\s\S]*?-----END (?:[A-Z ]{1,32} )?PRIVATE KEY-----/;
|
|
21
|
+
const reverse = (text) => text.split("").reverse().join("");
|
|
22
|
+
/** A line break, or a run of "…" or of three or more ".": where a text may have been elided. */
|
|
23
|
+
const EDGE_BOUNDARY = /\n|…+|\.{3,}/g;
|
|
24
|
+
const SPACE_OR_TAB = /[ \t]/;
|
|
25
|
+
/**
|
|
26
|
+
* The [start, end) of each elision boundary in `text`: EDGE_BOUNDARY, widened over an opening
|
|
27
|
+
* bracket just before an ellipsis or a closing one just after it ("[... omitted ...]"), and over
|
|
28
|
+
* any spaces or tabs around it. Widened by hand, never past the previous boundary, so the scan is
|
|
29
|
+
* linear (a regex with leading `[ \t]*` backtracks quadratically on a long run of spaces).
|
|
30
|
+
*/
|
|
31
|
+
function edgeBoundaries(text) {
|
|
32
|
+
const found = [];
|
|
33
|
+
let floor = 0;
|
|
34
|
+
for (const match of text.matchAll(EDGE_BOUNDARY)) {
|
|
35
|
+
let start = match.index;
|
|
36
|
+
let end = start + match[0].length;
|
|
37
|
+
if (match[0] !== "\n") {
|
|
38
|
+
if (start > floor && "[(<".includes(text[start - 1]))
|
|
39
|
+
start--;
|
|
40
|
+
while (start > floor && SPACE_OR_TAB.test(text[start - 1]))
|
|
41
|
+
start--;
|
|
42
|
+
if (end < text.length && "])>".includes(text[end]))
|
|
43
|
+
end++;
|
|
44
|
+
while (end < text.length && SPACE_OR_TAB.test(text[end]))
|
|
45
|
+
end++;
|
|
46
|
+
}
|
|
47
|
+
// A widened end may run into the next match; that match then starts at or after it.
|
|
48
|
+
if (start < floor)
|
|
49
|
+
start = floor;
|
|
50
|
+
if (end <= floor)
|
|
51
|
+
continue;
|
|
52
|
+
found.push([start, end]);
|
|
53
|
+
floor = end;
|
|
54
|
+
}
|
|
55
|
+
return found;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* `text` collapsed as summaries are (collapseWhitespace: runs of whitespace become one space,
|
|
59
|
+
* trimmed), with each collapsed character's [from, to) span in `text`.
|
|
60
|
+
*/
|
|
61
|
+
export function collapseWithMap(text) {
|
|
62
|
+
let start = 0;
|
|
63
|
+
let end = text.length;
|
|
64
|
+
while (start < end && WS.test(text[start]))
|
|
65
|
+
start++;
|
|
66
|
+
while (end > start && WS.test(text[end - 1]))
|
|
67
|
+
end--;
|
|
68
|
+
const parts = [];
|
|
69
|
+
const from = [];
|
|
70
|
+
const to = [];
|
|
71
|
+
for (let i = start; i < end;) {
|
|
72
|
+
if (WS.test(text[i])) {
|
|
73
|
+
const run = i;
|
|
74
|
+
while (i < end && WS.test(text[i]))
|
|
75
|
+
i++;
|
|
76
|
+
parts.push(" ");
|
|
77
|
+
from.push(run);
|
|
78
|
+
to.push(i);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
parts.push(text[i]);
|
|
82
|
+
from.push(i);
|
|
83
|
+
to.push(i + 1);
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { collapsed: parts.join(""), from, to };
|
|
88
|
+
}
|
|
89
|
+
/** Forms long enough for an edge check (a proper prefix of at least the minimum), by their first characters. */
|
|
90
|
+
function byStart(forms) {
|
|
91
|
+
const index = new Map();
|
|
92
|
+
for (const form of forms) {
|
|
93
|
+
if (form.length <= MIN_REDACTABLE_SECRET_LENGTH)
|
|
94
|
+
continue;
|
|
95
|
+
const start = form.slice(0, MIN_REDACTABLE_SECRET_LENGTH);
|
|
96
|
+
const same = index.get(start);
|
|
97
|
+
if (same)
|
|
98
|
+
same.push(form);
|
|
99
|
+
else
|
|
100
|
+
index.set(start, [form]);
|
|
101
|
+
}
|
|
102
|
+
return index;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The forms `subject` could end in a proper prefix of (secretTail's matches are at least the minimum
|
|
106
|
+
* long, so the subject holds the form's first MIN_REDACTABLE_SECRET_LENGTH characters): only these
|
|
107
|
+
* are scanned, so a line costs about its own length, however many secret values a run has.
|
|
108
|
+
* Longest first, as secretForms orders them.
|
|
109
|
+
*/
|
|
110
|
+
function candidates(subject, index) {
|
|
111
|
+
const starts = new Set();
|
|
112
|
+
for (let i = 0; i + MIN_REDACTABLE_SECRET_LENGTH <= subject.length; i++) {
|
|
113
|
+
starts.add(subject.slice(i, i + MIN_REDACTABLE_SECRET_LENGTH));
|
|
114
|
+
}
|
|
115
|
+
const found = [];
|
|
116
|
+
for (const start of starts)
|
|
117
|
+
found.push(...(index.get(start) ?? []));
|
|
118
|
+
return found.sort((a, b) => b.length - a.length);
|
|
119
|
+
}
|
|
120
|
+
/** The most a cut head's partial first line drop takes (afterCutHead). */
|
|
121
|
+
export const CUT_HEAD_DROP_CHARS = 256;
|
|
122
|
+
/**
|
|
123
|
+
* A text cut at its head, without its partial first line: up to and including the first line
|
|
124
|
+
* break when one falls within CUT_HEAD_DROP_CHARS of the cut, else exactly that many characters
|
|
125
|
+
* (a single-line output, such as a JSON result, keeps the rest of its end).
|
|
126
|
+
*/
|
|
127
|
+
const afterCutHead = (text) => {
|
|
128
|
+
const at = text.indexOf("\n");
|
|
129
|
+
return at >= 0 && at < CUT_HEAD_DROP_CHARS ? text.slice(at + 1) : text.slice(CUT_HEAD_DROP_CHARS);
|
|
130
|
+
};
|
|
131
|
+
const headCut = (text, max) => (text.length > max ? `${text.slice(0, max - 1)}…` : text);
|
|
132
|
+
/** A tool step's stored detail with its output appended, within MAX_STEP_DETAIL_CHARS. */
|
|
133
|
+
export function joinDetail(existing, suffix) {
|
|
134
|
+
return `${existing ?? ""}${suffix}`.slice(0, MAX_STEP_DETAIL_CHARS);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Detail texts for one batch, against every secret value delivered to the run (the agent's and the
|
|
138
|
+
* run's own). The forms, and each form's KMP table for the edge checks, are built once per batch.
|
|
139
|
+
*/
|
|
140
|
+
export function stepDetailer(secretValues) {
|
|
141
|
+
const forms = secretForms(secretValues);
|
|
142
|
+
const reversedForms = forms.map(reverse);
|
|
143
|
+
const tails = new Map();
|
|
144
|
+
const heads = new Map();
|
|
145
|
+
const formsByStart = byStart(forms);
|
|
146
|
+
const reversedByStart = byStart(reversedForms);
|
|
147
|
+
/**
|
|
148
|
+
* The same edge checks at every boundary inside `text`: each line break, each run of "…", and
|
|
149
|
+
* each run of three or more "." (every known truncation marker holds one: "…N tokens
|
|
150
|
+
* truncated…", "[... omitted N of M lines ...]"). The longest secret start each piece ends in
|
|
151
|
+
* before a boundary, and the longest secret end each piece starts with after one (at least
|
|
152
|
+
* MIN_REDACTABLE_SECRET_LENGTH, as at the text's own edges). A coding agent may elide the middle
|
|
153
|
+
* of a long output (or input) before the model sees it, on its own line or mid-line, leaving a
|
|
154
|
+
* delivered secret's start before the marker and its end after it, neither an exact-value match.
|
|
155
|
+
* Each match is masked only where it was found, at that boundary. A piece is scanned only for
|
|
156
|
+
* the forms whose first characters it holds (candidates), and no further back than its own start,
|
|
157
|
+
* so the cost stays near linear in the text however many secret values the run has.
|
|
158
|
+
*/
|
|
159
|
+
const boundaryEdgeSpans = (text) => {
|
|
160
|
+
const spans = [];
|
|
161
|
+
const pieces = [];
|
|
162
|
+
let start = 0;
|
|
163
|
+
for (const [from, to] of edgeBoundaries(text)) {
|
|
164
|
+
pieces.push([start, from]);
|
|
165
|
+
start = to;
|
|
166
|
+
}
|
|
167
|
+
pieces.push([start, text.length]);
|
|
168
|
+
for (const [from, to] of pieces) {
|
|
169
|
+
if (to <= from)
|
|
170
|
+
continue;
|
|
171
|
+
const piece = text.slice(from, to);
|
|
172
|
+
if (from > 0) {
|
|
173
|
+
const reversed = reverse(piece);
|
|
174
|
+
const head = secretTail(reversed, candidates(reversed, reversedByStart), heads).length;
|
|
175
|
+
if (head > 0)
|
|
176
|
+
spans.push([from, from + head]);
|
|
177
|
+
}
|
|
178
|
+
if (to < text.length) {
|
|
179
|
+
const tail = secretTail(piece, candidates(piece, formsByStart), tails).length;
|
|
180
|
+
if (tail > 0)
|
|
181
|
+
spans.push([to - tail, to]);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return spans;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* `raw` with every occurrence of every form masked, as written and in its collapsed form, plus
|
|
188
|
+
* the longest secret start it ends in (every text: a stream can stop mid-secret without saying
|
|
189
|
+
* so) and, when its head was cut, the longest secret end it starts with; then token shapes.
|
|
190
|
+
*/
|
|
191
|
+
const edges = (subject, headWasCut) => {
|
|
192
|
+
const found = [secretTail(subject, forms, tails)];
|
|
193
|
+
if (headWasCut)
|
|
194
|
+
found.push(reverse(secretTail(reverse(subject), reversedForms, heads)));
|
|
195
|
+
return found.filter(Boolean);
|
|
196
|
+
};
|
|
197
|
+
/** The spans of `text` as written: every form, the text's edges, and every boundary's edges. */
|
|
198
|
+
const asWrittenSpans = (text, headWasCut) => [
|
|
199
|
+
...secretSpans(text, [...forms, ...edges(text, headWasCut)], 1),
|
|
200
|
+
...boundaryEdgeSpans(text),
|
|
201
|
+
];
|
|
202
|
+
const redact = (raw, headWasCut) => {
|
|
203
|
+
const text = raw.slice(0, MAX_STEP_TEXT_CHARS);
|
|
204
|
+
const { collapsed, from, to } = collapseWithMap(text);
|
|
205
|
+
const asWritten = asWrittenSpans(text, headWasCut);
|
|
206
|
+
const viaCollapsed = secretSpans(collapsed, [...forms, ...edges(collapsed, headWasCut)], 1).map(([start, end]) => [from[start], to[end - 1]]);
|
|
207
|
+
const masked = maskSpans(text, mergeSpans([...asWritten, ...viaCollapsed]), REDACTED);
|
|
208
|
+
// Token shapes (and Bearer values) after the exact values, as redactSecrets does for summaries.
|
|
209
|
+
const shaped = redactSecrets(masked);
|
|
210
|
+
const open = shaped.replace(PEM_BEGIN_TO_END, REDACTED);
|
|
211
|
+
return headWasCut ? open.replace(PEM_START_TO_END, REDACTED) : open;
|
|
212
|
+
};
|
|
213
|
+
return {
|
|
214
|
+
premask(raw, headWasCut, marker) {
|
|
215
|
+
return maskSpans(raw, mergeSpans(asWrittenSpans(raw, headWasCut)), marker);
|
|
216
|
+
},
|
|
217
|
+
step(step) {
|
|
218
|
+
if (step.kind === "said")
|
|
219
|
+
return headCut(redact(step.text, false), DETAIL_SAID_CHARS);
|
|
220
|
+
return headCut(redact(step.input ?? step.text, false), DETAIL_INPUT_CHARS);
|
|
221
|
+
},
|
|
222
|
+
output(result) {
|
|
223
|
+
const source = tailOf(result.output);
|
|
224
|
+
const headWasCut = result.outputCut === true || source.cut;
|
|
225
|
+
// Redacted on everything available first. A text cut at its head then starts mid-line, where
|
|
226
|
+
// a token shape's anchor (a label, a scheme, a BEGIN line) may be gone, so the partial first
|
|
227
|
+
// line (at most CUT_HEAD_DROP_CHARS of it) is dropped, after the 2 KiB cut as well as after
|
|
228
|
+
// the source's.
|
|
229
|
+
let text = redact(source.text, headWasCut);
|
|
230
|
+
let cut = headWasCut;
|
|
231
|
+
if (cut)
|
|
232
|
+
text = afterCutHead(text);
|
|
233
|
+
if (text.length > DETAIL_OUTPUT_CHARS - 1) {
|
|
234
|
+
text = afterCutHead(text.slice(text.length - (DETAIL_OUTPUT_CHARS - 1)));
|
|
235
|
+
cut = true;
|
|
236
|
+
}
|
|
237
|
+
return `${DETAIL_OUTPUT_HEADING}${cut ? "…" : ""}${text}`;
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ExtractedResult, ExtractedStep, StepStatus } from "./types.js";
|
|
2
|
+
/** What an extractor keeps beyond the summary: the detail level's raw input and output tails. Off by default. */
|
|
3
|
+
export interface StepCaptureOptions {
|
|
4
|
+
detail?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export type StepWireProtocol = "openai-responses" | "anthropic-messages";
|
|
7
|
+
export interface StreamStepExtractor {
|
|
8
|
+
/** Reads one SSE frame (the text between blank lines). Never throws. */
|
|
9
|
+
consume(frame: string): void;
|
|
10
|
+
/** The steps completed since the last call. */
|
|
11
|
+
take(): ExtractedStep[];
|
|
12
|
+
/**
|
|
13
|
+
* The steps left when the reply has ended. When it was cut (it ended without its terminal event,
|
|
14
|
+
* or stopped at the output limit), its open text is kept and the last text is marked truncated; a
|
|
15
|
+
* tool call still open never ran, so it is no step. Never throws.
|
|
16
|
+
*/
|
|
17
|
+
finish(): ExtractedStep[];
|
|
18
|
+
}
|
|
19
|
+
export declare const MAX_RESULTS_PER_REQUEST = 64;
|
|
20
|
+
/** Anthropic Messages streams: input_json_delta assembled per block index, emitted on content_block_stop. */
|
|
21
|
+
export declare class AnthropicStreamSteps implements StreamStepExtractor {
|
|
22
|
+
private readonly options?;
|
|
23
|
+
private messageId;
|
|
24
|
+
private readonly blocks;
|
|
25
|
+
private done;
|
|
26
|
+
private stopped;
|
|
27
|
+
private cutStop;
|
|
28
|
+
constructor(options?: StepCaptureOptions | undefined);
|
|
29
|
+
consume(frame: string): void;
|
|
30
|
+
take(): ExtractedStep[];
|
|
31
|
+
finish(): ExtractedStep[];
|
|
32
|
+
private read;
|
|
33
|
+
}
|
|
34
|
+
/** One Responses output item as a step: function_call, custom_tool_call, or an assistant message. */
|
|
35
|
+
export declare function openAiItemStep(value: unknown, options?: StepCaptureOptions): ExtractedStep | undefined;
|
|
36
|
+
/** OpenAI Responses streams: one step per response.output_item.done. */
|
|
37
|
+
export declare class OpenAiStreamSteps implements StreamStepExtractor {
|
|
38
|
+
private readonly options?;
|
|
39
|
+
private done;
|
|
40
|
+
private completed;
|
|
41
|
+
constructor(options?: StepCaptureOptions | undefined);
|
|
42
|
+
consume(frame: string): void;
|
|
43
|
+
take(): ExtractedStep[];
|
|
44
|
+
finish(): ExtractedStep[];
|
|
45
|
+
}
|
|
46
|
+
export declare function streamStepExtractor(protocol: StepWireProtocol, options?: StepCaptureOptions): StreamStepExtractor;
|
|
47
|
+
/** A whole (non-stream) reply's steps. */
|
|
48
|
+
export declare function stepsFromJson(protocol: StepWireProtocol, value: unknown, options?: StepCaptureOptions): ExtractedStep[];
|
|
49
|
+
/** A result's status from its first lines: an exit line wins, else the error flag. */
|
|
50
|
+
export declare function statusFromOutput(head: string, isError: boolean): StepStatus;
|
|
51
|
+
/** The results a request carries for the turn before it: the newest part of the history only. */
|
|
52
|
+
export declare function resultsFromRequest(protocol: StepWireProtocol, value: unknown, options?: StepCaptureOptions): ExtractedResult[];
|