@geminixiang/mikan 1.0.0-beta.80 → 1.0.0-beta.82
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/CHANGELOG.md +27 -0
- package/dist/adapters/github/bot.d.ts.map +1 -1
- package/dist/adapters/github/bot.js +4 -4
- package/dist/adapters/github/bot.js.map +1 -1
- package/dist/adapters/github/client.d.ts +4 -0
- package/dist/adapters/github/client.d.ts.map +1 -1
- package/dist/adapters/github/client.js +41 -23
- package/dist/adapters/github/client.js.map +1 -1
- package/dist/adapters/github/github-ops.js +16 -12
- package/dist/adapters/github/github-ops.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +6 -3
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/web/server.d.ts +2 -0
- package/dist/adapters/web/server.d.ts.map +1 -1
- package/dist/adapters/web/server.js +11 -4
- package/dist/adapters/web/server.js.map +1 -1
- package/dist/adapters/web/session-view/portal.d.ts.map +1 -1
- package/dist/adapters/web/session-view/portal.js +84 -63
- package/dist/adapters/web/session-view/portal.js.map +1 -1
- package/dist/adapters/web/session-view/types.d.ts +2 -0
- package/dist/adapters/web/session-view/types.d.ts.map +1 -1
- package/dist/adapters/web/session-view/types.js.map +1 -1
- package/dist/env-manifest.d.ts +1 -0
- package/dist/env-manifest.d.ts.map +1 -1
- package/dist/env-manifest.js +7 -0
- package/dist/env-manifest.js.map +1 -1
- package/dist/harness/loop-guard.d.ts +10 -0
- package/dist/harness/loop-guard.d.ts.map +1 -0
- package/dist/harness/loop-guard.js +111 -0
- package/dist/harness/loop-guard.js.map +1 -0
- package/dist/harness/presenter.d.ts.map +1 -1
- package/dist/harness/presenter.js +159 -142
- package/dist/harness/presenter.js.map +1 -1
- package/dist/harness/prompt.d.ts +1 -1
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +14 -21
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/run-events.d.ts +10 -0
- package/dist/harness/run-events.d.ts.map +1 -0
- package/dist/harness/run-events.js +129 -0
- package/dist/harness/run-events.js.map +1 -0
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +79 -49
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session.d.ts +5 -0
- package/dist/harness/session.d.ts.map +1 -1
- package/dist/harness/session.js +71 -1
- package/dist/harness/session.js.map +1 -1
- package/dist/harness/tools/react.d.ts +1 -0
- package/dist/harness/tools/react.d.ts.map +1 -1
- package/dist/harness/tools/react.js +3 -2
- package/dist/harness/tools/react.js.map +1 -1
- package/dist/harness/types.d.ts +61 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/main.js +11 -8
- package/dist/main.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +1 -0
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +2 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/adapters/web/session-view/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,qBAAqB,CAAC;IAC/B,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/adapters/web/session-view/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,qBAAqB,CAAC;IAC/B,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACtD,SAAS,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,KAAK,GAAG,OAAO,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/adapters/web/session-view/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MessagingEventHandler, MessagingBot, PlatformName } from \"../../../types.js\";\nimport type { TokenRecord } from \"../types.js\";\n\nexport interface SessionViewInteractiveOptions {\n handler: MessagingEventHandler;\n botsByPlatform: Partial<Record<string, MessagingBot>>;\n}\n\nexport interface SessionViewItem {\n kind: \"user\" | \"assistant\" | \"tool\" | \"system\";\n title: string;\n body?: string;\n meta?: string;\n tone?: \"default\" | \"ok\" | \"err\" | \"muted\";\n entryId?: string;\n threads?: SessionViewRelation[];\n}\n\nexport interface SessionViewRelation {\n kind: \"parent\" | \"thread\";\n fileName: string;\n sessionId: string;\n title: string;\n updatedAt: string;\n entryCount: number;\n summary?: string;\n anchorEntryId?: string;\n}\n\nexport interface SessionViewModel {\n sessionId: string;\n fileName: string;\n title: string;\n createdAt: string;\n updatedAt: string;\n entryCount: number;\n items: SessionViewItem[];\n parent?: SessionViewRelation;\n threads: SessionViewRelation[];\n}\n\nexport interface SessionViewToken extends TokenRecord {\n platform: PlatformName;\n platformUserId: string;\n platformUserName?: string;\n conversationId: string;\n sessionKey: string;\n sessionFile: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/adapters/web/session-view/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { RunEventHub } from \"../../../harness/run-events.js\";\nimport type { MessagingEventHandler, MessagingBot, PlatformName } from \"../../../types.js\";\nimport type { TokenRecord } from \"../types.js\";\n\nexport interface SessionViewInteractiveOptions {\n handler: MessagingEventHandler;\n botsByPlatform: Partial<Record<string, MessagingBot>>;\n runEvents: RunEventHub;\n}\n\nexport interface SessionViewItem {\n kind: \"user\" | \"assistant\" | \"tool\" | \"system\";\n title: string;\n body?: string;\n meta?: string;\n tone?: \"default\" | \"ok\" | \"err\" | \"muted\";\n entryId?: string;\n threads?: SessionViewRelation[];\n}\n\nexport interface SessionViewRelation {\n kind: \"parent\" | \"thread\";\n fileName: string;\n sessionId: string;\n title: string;\n updatedAt: string;\n entryCount: number;\n summary?: string;\n anchorEntryId?: string;\n}\n\nexport interface SessionViewModel {\n sessionId: string;\n fileName: string;\n title: string;\n createdAt: string;\n updatedAt: string;\n entryCount: number;\n items: SessionViewItem[];\n parent?: SessionViewRelation;\n threads: SessionViewRelation[];\n}\n\nexport interface SessionViewToken extends TokenRecord {\n platform: PlatformName;\n platformUserId: string;\n platformUserName?: string;\n conversationId: string;\n sessionKey: string;\n sessionFile: string;\n}\n"]}
|
package/dist/env-manifest.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare function manifestVarNames(options?: {
|
|
|
12
12
|
deployOnly?: boolean;
|
|
13
13
|
}): string[];
|
|
14
14
|
export declare function envReport(env?: EnvLookup): string;
|
|
15
|
+
export declare function resolveLinkListenHost(read?: (name: string) => string | undefined): string;
|
|
15
16
|
export declare function resolveLinkBaseUrl(): string | undefined;
|
|
16
17
|
export {};
|
|
17
18
|
//# sourceMappingURL=env-manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-manifest.d.ts","sourceRoot":"","sources":["../src/env-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMxD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAG/D;AAED,eAAO,MAAM,YAAY,EAAE,SAAS,QAAQ,
|
|
1
|
+
{"version":3,"file":"env-manifest.d.ts","sourceRoot":"","sources":["../src/env-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMxD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAG/D;AAED,eAAO,MAAM,YAAY,EAAE,SAAS,QAAQ,EAiL3C,CAAC;AAEF,KAAK,SAAS,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAEtD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,SAAmB,GAAG,OAAO,CAO/E;AAED,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,SAAmB,GAAG,MAAM,EAAE,CAIrE;AAQD,wBAAgB,kBAAkB,IAAI,MAAM,CAK3C;AAED,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAI1C;AAED,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CAM7E;AAED,wBAAgB,SAAS,CAAC,GAAG,GAAE,SAAmB,GAAG,MAAM,CAuB1D;AAED,wBAAgB,qBAAqB,CACnC,IAAI,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAmB,GACnD,MAAM,CAER;AAED,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAIvD"}
|
package/dist/env-manifest.js
CHANGED
|
@@ -92,6 +92,10 @@ export const ENV_MANIFEST = [
|
|
|
92
92
|
vars: [
|
|
93
93
|
{ name: "LINK_URL", doc: "Externally visible base URL, e.g. https://mikan.example.com" },
|
|
94
94
|
{ name: "LINK_PORT", doc: "Listen port (default 8181 when LINK_URL is set)" },
|
|
95
|
+
{
|
|
96
|
+
name: "LINK_HOST",
|
|
97
|
+
doc: "Listen address (default 127.0.0.1, for a reverse proxy on the same host)",
|
|
98
|
+
},
|
|
95
99
|
{ name: "GITHUB_OAUTH_CLIENT_ID", doc: "GitHub OAuth app for /login linking" },
|
|
96
100
|
{ name: "GITHUB_OAUTH_CLIENT_SECRET", secret: true, doc: "GitHub OAuth app secret" },
|
|
97
101
|
{ name: "GOOGLE_WORKSPACE_CLI_CLIENT_ID", doc: "Google Workspace OAuth client for /login" },
|
|
@@ -240,6 +244,9 @@ export function envReport(env = readEnv) {
|
|
|
240
244
|
lines.push("Each var also accepts a MIKAN_-prefixed alias (e.g. MIKAN_LINK_URL).");
|
|
241
245
|
return lines.join("\n");
|
|
242
246
|
}
|
|
247
|
+
export function resolveLinkListenHost(read = readEnv) {
|
|
248
|
+
return read("LINK_HOST") ?? "127.0.0.1";
|
|
249
|
+
}
|
|
243
250
|
export function resolveLinkBaseUrl() {
|
|
244
251
|
const raw = readEnv("LINK_URL");
|
|
245
252
|
if (!raw)
|
package/dist/env-manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-manifest.js","sourceRoot":"","sources":["../src/env-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EnvGroup } from \"./types.js\";\n\nexport function readEnv(name: string): string | undefined {\n const raw = process.env[name]?.trim();\n if (raw) return raw;\n\n const prefixed = process.env[`MIKAN_${name}`]?.trim();\n return prefixed || undefined;\n}\n\nexport function readStandardEnv(name: string): string | undefined {\n return process.env[name]?.trim() || undefined;\n}\n\nexport function setEnvAliases(name: string, value: string): void {\n process.env[name] = value;\n process.env[`MIKAN_${name}`] = value;\n}\n\nexport const ENV_MANIFEST: readonly EnvGroup[] = [\n {\n key: \"slack\",\n title: \"Slack\",\n kind: \"platform\",\n vars: [\n {\n name: \"SLACK_APP_TOKEN\",\n required: true,\n secret: true,\n doc: \"Socket-mode app token (xapp-…)\",\n },\n { name: \"SLACK_BOT_TOKEN\", required: true, secret: true, doc: \"Bot token (xoxb-…)\" },\n ],\n },\n {\n key: \"telegram\",\n title: \"Telegram\",\n kind: \"platform\",\n vars: [{ name: \"TELEGRAM_BOT_TOKEN\", required: true, secret: true, doc: \"BotFather token\" }],\n },\n {\n key: \"discord\",\n title: \"Discord\",\n kind: \"platform\",\n vars: [{ name: \"DISCORD_BOT_TOKEN\", required: true, secret: true, doc: \"Bot token\" }],\n },\n {\n key: \"github\",\n title: \"GitHub\",\n kind: \"platform\",\n doc: \"Issue/PR conversations via a GitHub App (polling; optional webhook poke)\",\n vars: [\n { name: \"GITHUB_APP_ID\", required: true, doc: \"GitHub App id\" },\n { name: \"GITHUB_INSTALLATION_ID\", required: true, doc: \"App installation id\" },\n {\n name: \"GITHUB_APP_PRIVATE_KEY_PATH\",\n doc: \"Path to the App private key .pem (preferred; keep outside any repo)\",\n },\n {\n name: \"GITHUB_APP_PRIVATE_KEY\",\n secret: true,\n deploy: false,\n doc: \"App private key PEM with literal \\\\n newlines (fallback)\",\n },\n {\n name: \"GITHUB_REPOS\",\n doc: \"Comma-separated owner/repo allowlist (default: all installed)\",\n },\n { name: \"GITHUB_POLL_INTERVAL\", doc: \"Poll interval in seconds (default 60)\" },\n {\n name: \"GITHUB_WEBHOOK_SECRET\",\n secret: true,\n doc: \"Webhook secret; when set, deliveries to /github/webhook trigger an immediate poll (needs LINK_PORT)\",\n },\n ],\n anyOf: [\"GITHUB_APP_PRIVATE_KEY\", \"GITHUB_APP_PRIVATE_KEY_PATH\"],\n },\n {\n key: \"llm\",\n title: \"LLM providers\",\n kind: \"feature\",\n vars: [\n { name: \"ANTHROPIC_API_KEY\", secret: true, doc: \"Anthropic API key\" },\n { name: \"OPENAI_API_KEY\", secret: true, doc: \"OpenAI API key\" },\n {\n name: \"OPENROUTER_API_KEY\",\n secret: true,\n doc: \"OpenRouter API key (chat models routed through OpenRouter, and harness/jev.ts's Jev client via @geminixiang/jev)\",\n },\n ],\n },\n {\n key: \"link\",\n title: \"Link/OAuth server\",\n kind: \"feature\",\n doc: \"Credential onboarding links, session view, and the Admin portal\",\n vars: [\n { name: \"LINK_URL\", doc: \"Externally visible base URL, e.g. https://mikan.example.com\" },\n { name: \"LINK_PORT\", doc: \"Listen port (default 8181 when LINK_URL is set)\" },\n { name: \"GITHUB_OAUTH_CLIENT_ID\", doc: \"GitHub OAuth app for /login linking\" },\n { name: \"GITHUB_OAUTH_CLIENT_SECRET\", secret: true, doc: \"GitHub OAuth app secret\" },\n { name: \"GOOGLE_WORKSPACE_CLI_CLIENT_ID\", doc: \"Google Workspace OAuth client for /login\" },\n {\n name: \"GOOGLE_WORKSPACE_CLI_CLIENT_SECRET\",\n secret: true,\n doc: \"Google Workspace OAuth secret\",\n },\n { name: \"GOOGLE_CLOUD_SDK_CLIENT_ID\", doc: \"Google Cloud SDK OAuth client for /login\" },\n {\n name: \"GOOGLE_CLOUD_SDK_CLIENT_SECRET\",\n secret: true,\n doc: \"Google Cloud SDK OAuth secret\",\n },\n ],\n },\n {\n key: \"openconnector\",\n title: \"OpenConnector\",\n kind: \"feature\",\n doc: \"Default open-connector MCP server and the admin token that mints per-conversation runtime tokens\",\n vars: [\n {\n name: \"OPENCONNECTOR_ENDPOINT\",\n doc: \"Default MCP endpoint used when a conversation does not declare open-connector\",\n },\n {\n name: \"OPENCONNECTOR_ADMIN_TOKEN\",\n secret: true,\n doc: \"Host-only admin token used to mint one runtime token per conversation for the default server\",\n },\n ],\n },\n {\n key: \"cloudflare\",\n title: \"Cloudflare sandbox\",\n kind: \"feature\",\n doc: \"For --sandbox=cloudflare:<id> via the bridge worker\",\n vars: [\n { name: \"CLOUDFLARE_SANDBOX_URL\", doc: \"Bridge worker URL\" },\n { name: \"CLOUDFLARE_SANDBOX_TOKEN\", secret: true, doc: \"Bridge worker auth token\" },\n ],\n },\n {\n key: \"observability\",\n title: \"Observability\",\n kind: \"feature\",\n vars: [\n { name: \"SENTRY_DSN\", secret: true, doc: \"Sentry DSN (settings.json sentry.dsn wins)\" },\n {\n name: \"SENTRY_ENVIRONMENT\",\n deploy: false,\n doc: \"Sentry environment tag (default production)\",\n },\n { name: \"SENTRY_ENABLED\", deploy: false, doc: \"Set to false to disable Sentry errors\" },\n { name: \"OTEL_SDK_DISABLED\", doc: \"Set to true to disable OpenTelemetry\" },\n { name: \"OTEL_SERVICE_NAME\", doc: \"OTLP service name (default mikan)\" },\n {\n name: \"OTEL_RESOURCE_ATTRIBUTES\",\n secret: true,\n doc: \"Comma-separated safe resource attrs\",\n },\n { name: \"OTEL_TRACES_EXPORTER\", doc: \"Trace exporter: otlp or none\" },\n { name: \"OTEL_METRICS_EXPORTER\", doc: \"Metrics exporter: otlp or none\" },\n { name: \"OTEL_EXPORTER_OTLP_ENDPOINT\", secret: true, doc: \"Base OTLP HTTP endpoint\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\", secret: true, doc: \"OTLP traces endpoint\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT\", secret: true, doc: \"OTLP metrics endpoint\" },\n { name: \"OTEL_EXPORTER_OTLP_HEADERS\", secret: true, doc: \"Shared OTLP auth headers\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_HEADERS\", secret: true, doc: \"OTLP trace headers\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_HEADERS\", secret: true, doc: \"OTLP metric headers\" },\n { name: \"OTEL_EXPORTER_OTLP_PROTOCOL\", doc: \"OTLP protocol; http/protobuf supported\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", doc: \"Trace protocol override\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_PROTOCOL\", doc: \"Metric protocol override\" },\n { name: \"OTEL_EXPORTER_OTLP_TIMEOUT\", doc: \"Shared OTLP timeout in milliseconds\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_TIMEOUT\", doc: \"Trace timeout in milliseconds\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_TIMEOUT\", doc: \"Metric timeout in milliseconds\" },\n { name: \"OTEL_METRIC_EXPORT_INTERVAL\", doc: \"Metric export interval in milliseconds\" },\n { name: \"OTEL_METRIC_EXPORT_TIMEOUT\", doc: \"Metric export timeout in milliseconds\" },\n ],\n },\n {\n key: \"runtime\",\n title: \"Runtime\",\n kind: \"feature\",\n vars: [\n { name: \"STATE_DIR\", deploy: false, doc: \"State dir override (same as --state-dir)\" },\n {\n name: \"HTTP_IDLE_TIMEOUT\",\n deploy: false,\n doc: \"Idle timeout in ms for outbound HTTP streams\",\n },\n ],\n },\n];\n\ntype EnvLookup = (name: string) => string | undefined;\n\nexport function platformIsActive(key: string, env: EnvLookup = readEnv): boolean {\n const group = ENV_MANIFEST.find((candidate) => candidate.key === key);\n if (!group) throw new Error(`Unknown env-manifest group: ${key}`);\n const required = group.vars.filter((spec) => spec.required);\n if (!required.every((spec) => env(spec.name))) return false;\n if (group.anyOf && !group.anyOf.some((name) => env(name))) return false;\n return true;\n}\n\nexport function activePlatformKeys(env: EnvLookup = readEnv): string[] {\n return ENV_MANIFEST.filter(\n (group) => group.kind === \"platform\" && platformIsActive(group.key, env),\n ).map((group) => group.key);\n}\n\nfunction platformRecipe(group: EnvGroup): string {\n const required = group.vars.filter((spec) => spec.required).map((spec) => spec.name);\n const alternative = group.anyOf ? ` + ${group.anyOf.join(\" | \")}` : \"\";\n return `${group.title}: ${required.join(\" + \")}${alternative}`;\n}\n\nexport function noPlatformsMessage(): string {\n const recipes = ENV_MANIFEST.filter((group) => group.kind === \"platform\")\n .map((group) => ` ${platformRecipe(group)}`)\n .join(\"\\n\");\n return `No platform tokens found. Set one of:\\n${recipes}`;\n}\n\nexport function envSummaryLines(): string[] {\n return ENV_MANIFEST.filter((group) => group.kind === \"platform\").map(\n (group) => ` ${platformRecipe(group)}`,\n );\n}\n\nexport function manifestVarNames(options?: { deployOnly?: boolean }): string[] {\n return ENV_MANIFEST.flatMap((group) =>\n group.vars\n .filter((spec) => !options?.deployOnly || spec.deploy !== false)\n .map((spec) => spec.name),\n );\n}\n\nexport function envReport(env: EnvLookup = readEnv): string {\n const lines: string[] = [];\n for (const group of ENV_MANIFEST) {\n const active =\n group.kind === \"platform\"\n ? platformIsActive(group.key, env)\n ? \" — active\"\n : \" — inactive\"\n : \"\";\n lines.push(`${group.title}${active}${group.doc ? ` · ${group.doc}` : \"\"}`);\n for (const spec of group.vars) {\n const status = env(spec.name) ? \"set\" : \"unset\";\n const marks = [spec.required ? \"required\" : \"\", spec.secret ? \"secret\" : \"\"]\n .filter(Boolean)\n .join(\", \");\n lines.push(\n ` ${spec.name.padEnd(36)} ${status.padEnd(6)}${marks ? ` [${marks}]` : \"\"} ${spec.doc}`,\n );\n }\n lines.push(\"\");\n }\n lines.push(\"Each var also accepts a MIKAN_-prefixed alias (e.g. MIKAN_LINK_URL).\");\n return lines.join(\"\\n\");\n}\n\nexport function resolveLinkBaseUrl(): string | undefined {\n const raw = readEnv(\"LINK_URL\");\n if (!raw) return undefined;\n return raw.replace(/\\/+$/, \"\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"env-manifest.js","sourceRoot":"","sources":["../src/env-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EnvGroup } from \"./types.js\";\n\nexport function readEnv(name: string): string | undefined {\n const raw = process.env[name]?.trim();\n if (raw) return raw;\n\n const prefixed = process.env[`MIKAN_${name}`]?.trim();\n return prefixed || undefined;\n}\n\nexport function readStandardEnv(name: string): string | undefined {\n return process.env[name]?.trim() || undefined;\n}\n\nexport function setEnvAliases(name: string, value: string): void {\n process.env[name] = value;\n process.env[`MIKAN_${name}`] = value;\n}\n\nexport const ENV_MANIFEST: readonly EnvGroup[] = [\n {\n key: \"slack\",\n title: \"Slack\",\n kind: \"platform\",\n vars: [\n {\n name: \"SLACK_APP_TOKEN\",\n required: true,\n secret: true,\n doc: \"Socket-mode app token (xapp-…)\",\n },\n { name: \"SLACK_BOT_TOKEN\", required: true, secret: true, doc: \"Bot token (xoxb-…)\" },\n ],\n },\n {\n key: \"telegram\",\n title: \"Telegram\",\n kind: \"platform\",\n vars: [{ name: \"TELEGRAM_BOT_TOKEN\", required: true, secret: true, doc: \"BotFather token\" }],\n },\n {\n key: \"discord\",\n title: \"Discord\",\n kind: \"platform\",\n vars: [{ name: \"DISCORD_BOT_TOKEN\", required: true, secret: true, doc: \"Bot token\" }],\n },\n {\n key: \"github\",\n title: \"GitHub\",\n kind: \"platform\",\n doc: \"Issue/PR conversations via a GitHub App (polling; optional webhook poke)\",\n vars: [\n { name: \"GITHUB_APP_ID\", required: true, doc: \"GitHub App id\" },\n { name: \"GITHUB_INSTALLATION_ID\", required: true, doc: \"App installation id\" },\n {\n name: \"GITHUB_APP_PRIVATE_KEY_PATH\",\n doc: \"Path to the App private key .pem (preferred; keep outside any repo)\",\n },\n {\n name: \"GITHUB_APP_PRIVATE_KEY\",\n secret: true,\n deploy: false,\n doc: \"App private key PEM with literal \\\\n newlines (fallback)\",\n },\n {\n name: \"GITHUB_REPOS\",\n doc: \"Comma-separated owner/repo allowlist (default: all installed)\",\n },\n { name: \"GITHUB_POLL_INTERVAL\", doc: \"Poll interval in seconds (default 60)\" },\n {\n name: \"GITHUB_WEBHOOK_SECRET\",\n secret: true,\n doc: \"Webhook secret; when set, deliveries to /github/webhook trigger an immediate poll (needs LINK_PORT)\",\n },\n ],\n anyOf: [\"GITHUB_APP_PRIVATE_KEY\", \"GITHUB_APP_PRIVATE_KEY_PATH\"],\n },\n {\n key: \"llm\",\n title: \"LLM providers\",\n kind: \"feature\",\n vars: [\n { name: \"ANTHROPIC_API_KEY\", secret: true, doc: \"Anthropic API key\" },\n { name: \"OPENAI_API_KEY\", secret: true, doc: \"OpenAI API key\" },\n {\n name: \"OPENROUTER_API_KEY\",\n secret: true,\n doc: \"OpenRouter API key (chat models routed through OpenRouter, and harness/jev.ts's Jev client via @geminixiang/jev)\",\n },\n ],\n },\n {\n key: \"link\",\n title: \"Link/OAuth server\",\n kind: \"feature\",\n doc: \"Credential onboarding links, session view, and the Admin portal\",\n vars: [\n { name: \"LINK_URL\", doc: \"Externally visible base URL, e.g. https://mikan.example.com\" },\n { name: \"LINK_PORT\", doc: \"Listen port (default 8181 when LINK_URL is set)\" },\n {\n name: \"LINK_HOST\",\n doc: \"Listen address (default 127.0.0.1, for a reverse proxy on the same host)\",\n },\n { name: \"GITHUB_OAUTH_CLIENT_ID\", doc: \"GitHub OAuth app for /login linking\" },\n { name: \"GITHUB_OAUTH_CLIENT_SECRET\", secret: true, doc: \"GitHub OAuth app secret\" },\n { name: \"GOOGLE_WORKSPACE_CLI_CLIENT_ID\", doc: \"Google Workspace OAuth client for /login\" },\n {\n name: \"GOOGLE_WORKSPACE_CLI_CLIENT_SECRET\",\n secret: true,\n doc: \"Google Workspace OAuth secret\",\n },\n { name: \"GOOGLE_CLOUD_SDK_CLIENT_ID\", doc: \"Google Cloud SDK OAuth client for /login\" },\n {\n name: \"GOOGLE_CLOUD_SDK_CLIENT_SECRET\",\n secret: true,\n doc: \"Google Cloud SDK OAuth secret\",\n },\n ],\n },\n {\n key: \"openconnector\",\n title: \"OpenConnector\",\n kind: \"feature\",\n doc: \"Default open-connector MCP server and the admin token that mints per-conversation runtime tokens\",\n vars: [\n {\n name: \"OPENCONNECTOR_ENDPOINT\",\n doc: \"Default MCP endpoint used when a conversation does not declare open-connector\",\n },\n {\n name: \"OPENCONNECTOR_ADMIN_TOKEN\",\n secret: true,\n doc: \"Host-only admin token used to mint one runtime token per conversation for the default server\",\n },\n ],\n },\n {\n key: \"cloudflare\",\n title: \"Cloudflare sandbox\",\n kind: \"feature\",\n doc: \"For --sandbox=cloudflare:<id> via the bridge worker\",\n vars: [\n { name: \"CLOUDFLARE_SANDBOX_URL\", doc: \"Bridge worker URL\" },\n { name: \"CLOUDFLARE_SANDBOX_TOKEN\", secret: true, doc: \"Bridge worker auth token\" },\n ],\n },\n {\n key: \"observability\",\n title: \"Observability\",\n kind: \"feature\",\n vars: [\n { name: \"SENTRY_DSN\", secret: true, doc: \"Sentry DSN (settings.json sentry.dsn wins)\" },\n {\n name: \"SENTRY_ENVIRONMENT\",\n deploy: false,\n doc: \"Sentry environment tag (default production)\",\n },\n { name: \"SENTRY_ENABLED\", deploy: false, doc: \"Set to false to disable Sentry errors\" },\n { name: \"OTEL_SDK_DISABLED\", doc: \"Set to true to disable OpenTelemetry\" },\n { name: \"OTEL_SERVICE_NAME\", doc: \"OTLP service name (default mikan)\" },\n {\n name: \"OTEL_RESOURCE_ATTRIBUTES\",\n secret: true,\n doc: \"Comma-separated safe resource attrs\",\n },\n { name: \"OTEL_TRACES_EXPORTER\", doc: \"Trace exporter: otlp or none\" },\n { name: \"OTEL_METRICS_EXPORTER\", doc: \"Metrics exporter: otlp or none\" },\n { name: \"OTEL_EXPORTER_OTLP_ENDPOINT\", secret: true, doc: \"Base OTLP HTTP endpoint\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\", secret: true, doc: \"OTLP traces endpoint\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT\", secret: true, doc: \"OTLP metrics endpoint\" },\n { name: \"OTEL_EXPORTER_OTLP_HEADERS\", secret: true, doc: \"Shared OTLP auth headers\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_HEADERS\", secret: true, doc: \"OTLP trace headers\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_HEADERS\", secret: true, doc: \"OTLP metric headers\" },\n { name: \"OTEL_EXPORTER_OTLP_PROTOCOL\", doc: \"OTLP protocol; http/protobuf supported\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", doc: \"Trace protocol override\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_PROTOCOL\", doc: \"Metric protocol override\" },\n { name: \"OTEL_EXPORTER_OTLP_TIMEOUT\", doc: \"Shared OTLP timeout in milliseconds\" },\n { name: \"OTEL_EXPORTER_OTLP_TRACES_TIMEOUT\", doc: \"Trace timeout in milliseconds\" },\n { name: \"OTEL_EXPORTER_OTLP_METRICS_TIMEOUT\", doc: \"Metric timeout in milliseconds\" },\n { name: \"OTEL_METRIC_EXPORT_INTERVAL\", doc: \"Metric export interval in milliseconds\" },\n { name: \"OTEL_METRIC_EXPORT_TIMEOUT\", doc: \"Metric export timeout in milliseconds\" },\n ],\n },\n {\n key: \"runtime\",\n title: \"Runtime\",\n kind: \"feature\",\n vars: [\n { name: \"STATE_DIR\", deploy: false, doc: \"State dir override (same as --state-dir)\" },\n {\n name: \"HTTP_IDLE_TIMEOUT\",\n deploy: false,\n doc: \"Idle timeout in ms for outbound HTTP streams\",\n },\n ],\n },\n];\n\ntype EnvLookup = (name: string) => string | undefined;\n\nexport function platformIsActive(key: string, env: EnvLookup = readEnv): boolean {\n const group = ENV_MANIFEST.find((candidate) => candidate.key === key);\n if (!group) throw new Error(`Unknown env-manifest group: ${key}`);\n const required = group.vars.filter((spec) => spec.required);\n if (!required.every((spec) => env(spec.name))) return false;\n if (group.anyOf && !group.anyOf.some((name) => env(name))) return false;\n return true;\n}\n\nexport function activePlatformKeys(env: EnvLookup = readEnv): string[] {\n return ENV_MANIFEST.filter(\n (group) => group.kind === \"platform\" && platformIsActive(group.key, env),\n ).map((group) => group.key);\n}\n\nfunction platformRecipe(group: EnvGroup): string {\n const required = group.vars.filter((spec) => spec.required).map((spec) => spec.name);\n const alternative = group.anyOf ? ` + ${group.anyOf.join(\" | \")}` : \"\";\n return `${group.title}: ${required.join(\" + \")}${alternative}`;\n}\n\nexport function noPlatformsMessage(): string {\n const recipes = ENV_MANIFEST.filter((group) => group.kind === \"platform\")\n .map((group) => ` ${platformRecipe(group)}`)\n .join(\"\\n\");\n return `No platform tokens found. Set one of:\\n${recipes}`;\n}\n\nexport function envSummaryLines(): string[] {\n return ENV_MANIFEST.filter((group) => group.kind === \"platform\").map(\n (group) => ` ${platformRecipe(group)}`,\n );\n}\n\nexport function manifestVarNames(options?: { deployOnly?: boolean }): string[] {\n return ENV_MANIFEST.flatMap((group) =>\n group.vars\n .filter((spec) => !options?.deployOnly || spec.deploy !== false)\n .map((spec) => spec.name),\n );\n}\n\nexport function envReport(env: EnvLookup = readEnv): string {\n const lines: string[] = [];\n for (const group of ENV_MANIFEST) {\n const active =\n group.kind === \"platform\"\n ? platformIsActive(group.key, env)\n ? \" — active\"\n : \" — inactive\"\n : \"\";\n lines.push(`${group.title}${active}${group.doc ? ` · ${group.doc}` : \"\"}`);\n for (const spec of group.vars) {\n const status = env(spec.name) ? \"set\" : \"unset\";\n const marks = [spec.required ? \"required\" : \"\", spec.secret ? \"secret\" : \"\"]\n .filter(Boolean)\n .join(\", \");\n lines.push(\n ` ${spec.name.padEnd(36)} ${status.padEnd(6)}${marks ? ` [${marks}]` : \"\"} ${spec.doc}`,\n );\n }\n lines.push(\"\");\n }\n lines.push(\"Each var also accepts a MIKAN_-prefixed alias (e.g. MIKAN_LINK_URL).\");\n return lines.join(\"\\n\");\n}\n\nexport function resolveLinkListenHost(\n read: (name: string) => string | undefined = readEnv,\n): string {\n return read(\"LINK_HOST\") ?? \"127.0.0.1\";\n}\n\nexport function resolveLinkBaseUrl(): string | undefined {\n const raw = readEnv(\"LINK_URL\");\n if (!raw) return undefined;\n return raw.replace(/\\/+$/, \"\");\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ToolLoopVerdict } from "./types.js";
|
|
2
|
+
export declare class ToolLoopGuard {
|
|
3
|
+
private readonly records;
|
|
4
|
+
private readonly cycleNotices;
|
|
5
|
+
observe(toolName: string, args: Record<string, unknown>): ToolLoopVerdict;
|
|
6
|
+
private identicalRunLength;
|
|
7
|
+
private cycleVerdict;
|
|
8
|
+
private cycleRepetitions;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=loop-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-guard.d.ts","sourceRoot":"","sources":["../../src/harness/loop-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAgBlD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAE1D,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CAwBxE;IAED,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,gBAAgB;CAiBzB"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const TRACK_WINDOW = 64;
|
|
2
|
+
const IDENTICAL_NOTICE_AT = 3;
|
|
3
|
+
const IDENTICAL_BLOCK_AT = 5;
|
|
4
|
+
const IDENTICAL_STOP_AT = 10;
|
|
5
|
+
const CYCLE_MIN_PERIOD = 2;
|
|
6
|
+
const CYCLE_MAX_PERIOD = 6;
|
|
7
|
+
const CYCLE_NOTICE_REPETITIONS = 3;
|
|
8
|
+
const CYCLE_RENOTICE_FACTOR = 2;
|
|
9
|
+
export class ToolLoopGuard {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.records = [];
|
|
12
|
+
this.cycleNotices = new Map();
|
|
13
|
+
}
|
|
14
|
+
observe(toolName, args) {
|
|
15
|
+
this.records.push({ toolName, signature: callSignature(toolName, args) });
|
|
16
|
+
if (this.records.length > TRACK_WINDOW)
|
|
17
|
+
this.records.shift();
|
|
18
|
+
const identical = this.identicalRunLength();
|
|
19
|
+
if (identical >= IDENTICAL_STOP_AT) {
|
|
20
|
+
return {
|
|
21
|
+
kind: "stop",
|
|
22
|
+
reason: `tool loop: ${toolName} called ${identical} times in a row with identical arguments`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (identical >= IDENTICAL_BLOCK_AT) {
|
|
26
|
+
return {
|
|
27
|
+
kind: "block",
|
|
28
|
+
reason: `${toolName} was called ${identical} times in a row with identical arguments, so this call was not executed. Its result would not change. Take a different approach, or tell the user what is blocking progress.`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (identical >= IDENTICAL_NOTICE_AT) {
|
|
32
|
+
return {
|
|
33
|
+
kind: "notice",
|
|
34
|
+
text: `[loop guard] This is call ${identical} in a row of ${toolName} with identical arguments. Repeating it returns the same result. If you are waiting for something to change, wait inside a single bounded command instead; otherwise change your approach.`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return this.cycleVerdict();
|
|
38
|
+
}
|
|
39
|
+
identicalRunLength() {
|
|
40
|
+
const last = this.records.at(-1);
|
|
41
|
+
let run = 0;
|
|
42
|
+
for (let index = this.records.length - 1; index >= 0; index--) {
|
|
43
|
+
if (this.records[index]?.signature !== last?.signature)
|
|
44
|
+
break;
|
|
45
|
+
run++;
|
|
46
|
+
}
|
|
47
|
+
return run;
|
|
48
|
+
}
|
|
49
|
+
cycleVerdict() {
|
|
50
|
+
const total = this.records.length;
|
|
51
|
+
for (let period = CYCLE_MIN_PERIOD; period <= CYCLE_MAX_PERIOD; period++) {
|
|
52
|
+
if (total < period * CYCLE_NOTICE_REPETITIONS)
|
|
53
|
+
continue;
|
|
54
|
+
const cycle = this.records.slice(total - period);
|
|
55
|
+
if (new Set(cycle.map((record) => record.signature)).size < 2)
|
|
56
|
+
continue;
|
|
57
|
+
const repetitions = this.cycleRepetitions(period);
|
|
58
|
+
if (repetitions < CYCLE_NOTICE_REPETITIONS)
|
|
59
|
+
continue;
|
|
60
|
+
const key = cycleKey(cycle);
|
|
61
|
+
const notified = this.cycleNotices.get(key);
|
|
62
|
+
if (notified !== undefined && repetitions < notified * CYCLE_RENOTICE_FACTOR) {
|
|
63
|
+
return { kind: "allow" };
|
|
64
|
+
}
|
|
65
|
+
this.cycleNotices.set(key, repetitions);
|
|
66
|
+
const tools = cycle.map((record) => record.toolName).join(" → ");
|
|
67
|
+
return {
|
|
68
|
+
kind: "notice",
|
|
69
|
+
text: `[loop guard] The same sequence of ${period} tool calls (${tools}) has repeated ${repetitions} times with identical arguments. It is not making progress; change your approach.`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return { kind: "allow" };
|
|
73
|
+
}
|
|
74
|
+
cycleRepetitions(period) {
|
|
75
|
+
const total = this.records.length;
|
|
76
|
+
let repetitions = 1;
|
|
77
|
+
while ((repetitions + 1) * period <= total) {
|
|
78
|
+
const blockStart = total - (repetitions + 1) * period;
|
|
79
|
+
for (let offset = 0; offset < period; offset++) {
|
|
80
|
+
if (this.records[blockStart + offset]?.signature !==
|
|
81
|
+
this.records[total - period + offset]?.signature) {
|
|
82
|
+
return repetitions;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
repetitions++;
|
|
86
|
+
}
|
|
87
|
+
return repetitions;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function cycleKey(cycle) {
|
|
91
|
+
return cycle
|
|
92
|
+
.map((record) => record.signature)
|
|
93
|
+
.toSorted()
|
|
94
|
+
.join("\n");
|
|
95
|
+
}
|
|
96
|
+
function callSignature(toolName, args) {
|
|
97
|
+
const { label: _label, ...identity } = args;
|
|
98
|
+
return `${toolName}\u0000${canonicalJson(identity)}`;
|
|
99
|
+
}
|
|
100
|
+
function canonicalJson(value) {
|
|
101
|
+
if (Array.isArray(value))
|
|
102
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
103
|
+
if (value !== null && typeof value === "object") {
|
|
104
|
+
const entries = Object.entries(value)
|
|
105
|
+
.toSorted(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
|
|
106
|
+
.map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`);
|
|
107
|
+
return `{${entries.join(",")}}`;
|
|
108
|
+
}
|
|
109
|
+
return JSON.stringify(value) ?? "null";
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=loop-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-guard.js","sourceRoot":"","sources":["../../src/harness/loop-guard.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ToolLoopVerdict } from \"./types.js\";\n\nconst TRACK_WINDOW = 64;\nconst IDENTICAL_NOTICE_AT = 3;\nconst IDENTICAL_BLOCK_AT = 5;\nconst IDENTICAL_STOP_AT = 10;\nconst CYCLE_MIN_PERIOD = 2;\nconst CYCLE_MAX_PERIOD = 6;\nconst CYCLE_NOTICE_REPETITIONS = 3;\nconst CYCLE_RENOTICE_FACTOR = 2;\n\ninterface CallRecord {\n toolName: string;\n signature: string;\n}\n\nexport class ToolLoopGuard {\n private readonly records: CallRecord[] = [];\n private readonly cycleNotices = new Map<string, number>();\n\n observe(toolName: string, args: Record<string, unknown>): ToolLoopVerdict {\n this.records.push({ toolName, signature: callSignature(toolName, args) });\n if (this.records.length > TRACK_WINDOW) this.records.shift();\n\n const identical = this.identicalRunLength();\n if (identical >= IDENTICAL_STOP_AT) {\n return {\n kind: \"stop\",\n reason: `tool loop: ${toolName} called ${identical} times in a row with identical arguments`,\n };\n }\n if (identical >= IDENTICAL_BLOCK_AT) {\n return {\n kind: \"block\",\n reason: `${toolName} was called ${identical} times in a row with identical arguments, so this call was not executed. Its result would not change. Take a different approach, or tell the user what is blocking progress.`,\n };\n }\n if (identical >= IDENTICAL_NOTICE_AT) {\n return {\n kind: \"notice\",\n text: `[loop guard] This is call ${identical} in a row of ${toolName} with identical arguments. Repeating it returns the same result. If you are waiting for something to change, wait inside a single bounded command instead; otherwise change your approach.`,\n };\n }\n return this.cycleVerdict();\n }\n\n private identicalRunLength(): number {\n const last = this.records.at(-1);\n let run = 0;\n for (let index = this.records.length - 1; index >= 0; index--) {\n if (this.records[index]?.signature !== last?.signature) break;\n run++;\n }\n return run;\n }\n\n private cycleVerdict(): ToolLoopVerdict {\n const total = this.records.length;\n for (let period = CYCLE_MIN_PERIOD; period <= CYCLE_MAX_PERIOD; period++) {\n if (total < period * CYCLE_NOTICE_REPETITIONS) continue;\n const cycle = this.records.slice(total - period);\n if (new Set(cycle.map((record) => record.signature)).size < 2) continue;\n const repetitions = this.cycleRepetitions(period);\n if (repetitions < CYCLE_NOTICE_REPETITIONS) continue;\n const key = cycleKey(cycle);\n const notified = this.cycleNotices.get(key);\n if (notified !== undefined && repetitions < notified * CYCLE_RENOTICE_FACTOR) {\n return { kind: \"allow\" };\n }\n this.cycleNotices.set(key, repetitions);\n const tools = cycle.map((record) => record.toolName).join(\" → \");\n return {\n kind: \"notice\",\n text: `[loop guard] The same sequence of ${period} tool calls (${tools}) has repeated ${repetitions} times with identical arguments. It is not making progress; change your approach.`,\n };\n }\n return { kind: \"allow\" };\n }\n\n private cycleRepetitions(period: number): number {\n const total = this.records.length;\n let repetitions = 1;\n while ((repetitions + 1) * period <= total) {\n const blockStart = total - (repetitions + 1) * period;\n for (let offset = 0; offset < period; offset++) {\n if (\n this.records[blockStart + offset]?.signature !==\n this.records[total - period + offset]?.signature\n ) {\n return repetitions;\n }\n }\n repetitions++;\n }\n return repetitions;\n }\n}\n\nfunction cycleKey(cycle: CallRecord[]): string {\n return cycle\n .map((record) => record.signature)\n .toSorted()\n .join(\"\\n\");\n}\n\nfunction callSignature(toolName: string, args: Record<string, unknown>): string {\n const { label: _label, ...identity } = args;\n return `${toolName}\\u0000${canonicalJson(identity)}`;\n}\n\nfunction canonicalJson(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonicalJson).join(\",\")}]`;\n if (value !== null && typeof value === \"object\") {\n const entries = Object.entries(value)\n .toSorted(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n .map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`);\n return `{${entries.join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presenter.d.ts","sourceRoot":"","sources":["../../src/harness/presenter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,0BAA0B,EAG1B,eAAe,EACf,sBAAsB,
|
|
1
|
+
{"version":3,"file":"presenter.d.ts","sourceRoot":"","sources":["../../src/harness/presenter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,0BAA0B,EAG1B,eAAe,EACf,sBAAsB,EAEtB,kBAAkB,EAClB,yBAAyB,EACzB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAMtD,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,aAAa,CAAC;AA2GnF,wBAAgB,cAAc,IAAI,kBAAkB,CAEnD;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CA6CjB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAGxE;AAED,wBAAgB,yBAAyB,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEzF;AAwID,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,qBAAqB,EAChC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,IAAI,CAAC,CAsBf;AA4ED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkG/E;AA0eD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,yBAAyB,GAAG,IAAI,CAyBlF"}
|