@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24
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 +102 -194
- package/README.zh-CN.md +115 -210
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-bootstrap.js +466 -35
- package/bin/gotry-inner.js +255 -36
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +2 -2
- package/client/client.js +174 -0
- package/cordis.gotry-patch.yml +70 -93
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +63 -148
- package/dist/capabilities/anything.js +89 -75
- package/dist/capabilities/artifacts.js +123 -104
- package/dist/capabilities/channel-health.js +65 -45
- package/dist/capabilities/channel-registry.js +108 -87
- package/dist/capabilities/doctor.js +357 -235
- package/dist/capabilities/effect.js +223 -309
- package/dist/capabilities/fact-log.js +28 -14
- package/dist/capabilities/flyai.js +245 -156
- package/dist/capabilities/ground-transfer.js +509 -0
- package/dist/capabilities/hbcli.js +144 -148
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/model-override.js +30 -10
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/resilience.js +50 -32
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
- package/dist/capabilities/session/adapters/dida-portal.js +206 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +169 -112
- package/dist/capabilities/session/benchmark.js +85 -149
- package/dist/capabilities/session/extension-bridge.js +320 -259
- package/dist/capabilities/session/extension-channel.js +57 -76
- package/dist/capabilities/session/extension-distribution.js +115 -119
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +55 -33
- package/dist/capabilities/session/health-watch.js +146 -154
- package/dist/capabilities/session/read-guard.js +55 -47
- package/dist/capabilities/session/static-flight-golden.js +49 -36
- package/dist/capabilities/session/transport.js +54 -61
- package/dist/capabilities/session/wizard.js +63 -93
- package/dist/capabilities/session-consent.js +143 -47
- package/dist/capabilities/session-login.js +95 -126
- package/dist/capabilities/session-search.js +391 -253
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +87 -73
- package/dist/capabilities/weather.js +163 -235
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
- package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
- package/dist/scripts/anything-tests.js +58 -62
- package/dist/scripts/artifact-client-contract-tests.js +69 -0
- package/dist/scripts/artifacts-capability-tests.js +235 -0
- package/dist/scripts/async-collect.js +26 -15
- package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
- package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
- package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
- package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
- package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
- package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
- package/dist/scripts/booking-executor-tests.js +80 -0
- package/dist/scripts/booking-recovery-chain-tests.js +182 -0
- package/dist/scripts/booking-saga-tests.js +61 -123
- package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
- package/dist/scripts/bootstrap-tests.js +1383 -128
- package/dist/scripts/build-changelog.js +89 -130
- package/dist/scripts/build-metrics-report.js +135 -143
- package/dist/scripts/changelog-tests.js +35 -82
- package/dist/scripts/channel-probe-tests.js +44 -116
- package/dist/scripts/channel-probe.js +84 -167
- package/dist/scripts/channel-registry-tests.js +97 -185
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +428 -120
- package/dist/scripts/dsh-artifact-e2e.js +150 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
- package/dist/scripts/dsh-runtime-closure.js +75 -63
- package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +165 -552
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +69 -242
- package/dist/scripts/evaluation-contract-tests.js +193 -499
- package/dist/scripts/extension-distribution-cli.js +19 -15
- package/dist/scripts/extension-distribution-tests.js +98 -211
- package/dist/scripts/extension-tests.js +366 -389
- package/dist/scripts/fact-gate-tests.js +725 -263
- package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
- package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
- package/dist/scripts/flight-malformed-tests.js +159 -0
- package/dist/scripts/flyai-tests.js +325 -68
- package/dist/scripts/g5-guard-tests.js +131 -0
- package/dist/scripts/g5-guard.js +189 -0
- package/dist/scripts/gen-lunar-anchors.js +106 -0
- package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +71 -90
- package/dist/scripts/hbcli-live-optin-tests.js +96 -0
- package/dist/scripts/hbcli-release-contract-tests.js +122 -0
- package/dist/scripts/hbcli-tests.js +41 -115
- package/dist/scripts/health-watch-cli.js +42 -28
- package/dist/scripts/hotel-date-gate-tests.js +496 -0
- package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
- package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
- package/dist/scripts/i18n-tests.js +16 -9
- package/dist/scripts/incident-tests.js +281 -87
- package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
- package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
- package/dist/scripts/issue-271-liveness-tests.js +547 -0
- package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
- package/dist/scripts/issue-289-model-retry-tests.js +441 -0
- package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
- package/dist/scripts/issue-338-home-city-e2e.js +577 -0
- package/dist/scripts/issue343-real-entry-e2e.js +160 -0
- package/dist/scripts/journey-tests.js +22 -27
- package/dist/scripts/kernel-manifest-evidence.js +109 -0
- package/dist/scripts/kernel-manifest-gate.js +126 -0
- package/dist/scripts/kernel-manifest-tests.js +212 -0
- package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
- package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
- package/dist/scripts/kernel-manifest.js +369 -0
- package/dist/scripts/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +325 -340
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
- package/dist/scripts/memory-capture-tests.js +242 -61
- package/dist/scripts/memory-decay-tests.js +18 -52
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +24 -12
- package/dist/scripts/memory-value-report.js +474 -222
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +62 -199
- package/dist/scripts/model-override-e2e.js +66 -105
- package/dist/scripts/nightly-evidence-tests.js +64 -89
- package/dist/scripts/nightly-evidence.js +108 -111
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/onboarding-tests.js +63 -88
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/persona-surface-guard-tests.js +37 -12
- package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +126 -227
- package/dist/scripts/price-drift-watch.js +209 -253
- package/dist/scripts/probe-poi-tests.js +52 -45
- package/dist/scripts/product-metrics.js +187 -273
- package/dist/scripts/publish-preverify.js +47 -41
- package/dist/scripts/realtime-pricing-tests.js +37 -76
- package/dist/scripts/replay-async.js +20 -18
- package/dist/scripts/replay-real.js +16 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +16 -12
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +66 -147
- package/dist/scripts/session-dida-live-e2e.js +151 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-login.js +14 -13
- package/dist/scripts/session-tests.js +545 -583
- package/dist/scripts/sf-live-benchmark.js +92 -110
- package/dist/scripts/sf-live-cli-tests.js +2 -9
- package/dist/scripts/sf-soft-score-tests.js +19 -60
- package/dist/scripts/sf-summary-tests.js +149 -0
- package/dist/scripts/sf-summary.js +466 -84
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +11 -10
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +12 -20
- package/dist/scripts/smoke.js +541 -422
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +549 -212
- package/dist/scripts/static-golden-tests.js +46 -180
- package/dist/scripts/time-eval-tests.js +210 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +46 -93
- package/dist/scripts/turn-handoff-collect.js +71 -99
- package/dist/scripts/turn-policy-tests.js +28 -29
- package/dist/scripts/typed-contract-canary.js +77 -162
- package/dist/scripts/tz-resolver-sanity.js +50 -0
- package/dist/scripts/tz-resolver-tests.js +584 -0
- package/dist/scripts/unified-tests.js +23 -19
- package/dist/scripts/visa-policy-tests.js +31 -44
- package/dist/scripts/weather-tests.js +121 -543
- package/dist/scripts/wish-channel-gate-tests.js +29 -86
- package/dist/scripts/write-gate-tests.js +522 -0
- package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
- package/dist/scripts/z3-lifecycle-tests.js +170 -0
- package/dist/scripts/z3-race-repeat-tests.js +39 -0
- package/dist/scripts/z3-race-tests.js +18 -12
- package/dist/src/artifact-gate.js +652 -221
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +55 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +194 -0
- package/dist/src/benchmark-agent-conformance.js +296 -262
- package/dist/src/benchmark-environment-bridge.js +298 -413
- package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
- package/dist/src/benchmark-tool-isolation.js +94 -67
- package/dist/src/bookable-facts.js +299 -174
- package/dist/src/booking-saga.js +64 -120
- package/dist/src/booking-surface/availability-policy.js +443 -576
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/contracts.js +24 -80
- package/dist/src/booking-surface/dsh-planner.js +510 -281
- package/dist/src/booking-surface/dsh-plugin.js +17 -1
- package/dist/src/booking-surface/error-codes.js +82 -10
- package/dist/src/booking-surface/index.js +0 -3
- package/dist/src/booking-surface/profile.js +10 -54
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +765 -891
- package/dist/src/booking-surface/server.js +200 -251
- package/dist/src/booking-surface/startup.js +58 -54
- package/dist/src/booking-surface/validation.js +150 -218
- package/dist/src/bridge.js +20 -13
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +82 -120
- package/dist/src/engine.js +253 -239
- package/dist/src/evaluation-cadence.js +72 -209
- package/dist/src/evaluation-contracts.js +220 -843
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/gotry-backend.js +70 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +18 -7
- package/dist/src/index.js +1425 -1629
- package/dist/src/journey.js +132 -81
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +257 -166
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/realtime-pricing.js +63 -72
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +310 -471
- package/dist/src/subagent-job-id-guard.js +58 -0
- package/dist/src/time-anchor.js +231 -33
- package/dist/src/tool-packet.js +20 -8
- package/dist/src/travel-slots.js +58 -35
- package/dist/src/travel-timeline.js +44 -63
- package/dist/src/turn-deadline.js +121 -127
- package/dist/src/turn-policy.js +61 -89
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +504 -381
- package/dist/src/wish-pool.js +39 -14
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +273 -7
- package/extension/README.md +4 -3
- package/extension/background.js +125 -14
- package/extension/content-bridge.js +23 -1
- package/extension/content-main.js +15 -4
- package/extension/manifest.json +16 -8
- package/package.json +251 -220
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +1 -1
- package/ts/capabilities/artifacts.ts +46 -9
- package/ts/capabilities/flyai.ts +156 -37
- package/ts/capabilities/hbcli.ts +1 -1
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
- package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
- package/ts/capabilities/session/extension-bridge.ts +226 -101
- package/ts/capabilities/session/extension-channel.ts +22 -9
- package/ts/capabilities/session/wizard.ts +2 -2
- package/ts/capabilities/session-consent.ts +98 -14
- package/ts/capabilities/session-login.ts +1 -0
- package/ts/capabilities/session-search.ts +315 -31
- package/ts/dsh-runtime/vendor/README.md +8 -4
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
- package/ts/package.json +236 -16
- package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
- package/ts/scripts/state-cli.ts +418 -51
- package/ts/src/artifact-gate.ts +561 -15
- package/ts/src/benchmark-environment-bridge.ts +37 -20
- package/ts/src/bookable-facts.ts +183 -7
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/dsh-planner.ts +240 -32
- package/ts/src/booking-surface/dsh-plugin.js +17 -1
- package/ts/src/booking-surface/error-codes.ts +75 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/server.ts +84 -51
- package/ts/src/booking-surface/validation.ts +2 -0
- package/ts/src/contracts.ts +12 -2
- package/ts/src/dsh-llm.ts +4 -8
- package/ts/src/index.ts +609 -90
- package/ts/src/loop.ts +116 -7
- package/ts/src/memory-capture.ts +227 -3
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/state-ledger.ts +47 -29
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +217 -13
- package/ts/src/unified.ts +316 -54
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline headless E2E for the agent turn boundary (ADR-24 v2).
|
|
3
|
+
*
|
|
4
|
+
* Exercises a clean installed-package binary on the PRODUCT path:
|
|
5
|
+
* bin/gotry-inner.js -> dist/src/index.js -> dsh headless -> local SSE relay
|
|
6
|
+
*
|
|
7
|
+
* 场景是失败轨迹的合成重放:deep-planning 类用户消息(10.3 婚礼 + 十几天
|
|
8
|
+
* + 请假 + IRW)进入路由,relay 把首个 planner 响应拖过硬阈(阈值经 env
|
|
9
|
+
* 压到秒级,exit 仍由路由决定为 handoff)→ 首个工具派发被拒并落
|
|
10
|
+
* `gotry_turn_handoff.v1` 工单 → 工具 schema 同步抑制 → 下一请求
|
|
11
|
+
* text-only → 二进制以含 ETA 语义的 final 收尾。工单落盘走
|
|
12
|
+
* GOTRY_TURN_HANDOFF_ROOT 钉死的隔离根,不触碰真实 gotry-state
|
|
13
|
+
* (巡检状态纪律);DSH_HOME 与 child cwd 均为临时目录,唯一模型端点
|
|
14
|
+
* 是 loopback。
|
|
15
|
+
*/
|
|
1
16
|
import assert from 'node:assert/strict';
|
|
2
17
|
import { createServer } from 'node:http';
|
|
3
18
|
import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
@@ -13,7 +28,9 @@ const HARD_MS = 10_000;
|
|
|
13
28
|
const RELAY_STALL_MS = HARD_MS + 1_000;
|
|
14
29
|
const HANDOFF = 'TURN_DEADLINE_HANDOFF';
|
|
15
30
|
const HANDOFF_SCHEMA = 'gotry_turn_handoff.v1';
|
|
16
|
-
|
|
31
|
+
/** 失败轨迹的合成等价消息:必须命中 deep-planning 路由。 */
|
|
32
|
+
const DEEP_MESSAGE = '2026年我还有6天IRW额度,我准备再请几天假,在国内待个十几天。'
|
|
33
|
+
+ '其中10.3要去湖南衡阳参加同学婚礼。请根据我的实际情况和偏好,给我安排行程';
|
|
17
34
|
function sse(data) {
|
|
18
35
|
return `data: ${JSON.stringify(data)}\n\n`;
|
|
19
36
|
}
|
|
@@ -22,156 +39,117 @@ function toolResponse(idSuffix) {
|
|
|
22
39
|
index: 0,
|
|
23
40
|
id: `deadline-call-${idSuffix}`,
|
|
24
41
|
type: 'function',
|
|
25
|
-
function: {
|
|
26
|
-
name: TOOL,
|
|
27
|
-
arguments: JSON.stringify({
|
|
28
|
-
query: {
|
|
29
|
-
limit: 1
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
}
|
|
42
|
+
function: { name: TOOL, arguments: JSON.stringify({ query: { limit: 1 } }) },
|
|
33
43
|
};
|
|
34
44
|
return sse({
|
|
35
45
|
id: `deadline-${idSuffix}`,
|
|
36
46
|
object: 'chat.completion.chunk',
|
|
37
47
|
created: 1,
|
|
38
48
|
model: 'synthetic-deadline-model',
|
|
39
|
-
choices: [
|
|
40
|
-
{
|
|
41
|
-
index: 0,
|
|
42
|
-
delta: {
|
|
43
|
-
role: 'assistant',
|
|
44
|
-
tool_calls: [
|
|
45
|
-
call
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
finish_reason: null
|
|
49
|
-
}
|
|
50
|
-
]
|
|
49
|
+
choices: [{ index: 0, delta: { role: 'assistant', tool_calls: [call] }, finish_reason: null }],
|
|
51
50
|
}) + sse({
|
|
52
51
|
id: `deadline-${idSuffix}-finish`,
|
|
53
52
|
object: 'chat.completion.chunk',
|
|
54
53
|
created: 1,
|
|
55
54
|
model: 'synthetic-deadline-model',
|
|
56
|
-
choices: [
|
|
57
|
-
{
|
|
58
|
-
index: 0,
|
|
59
|
-
delta: {},
|
|
60
|
-
finish_reason: 'tool_calls'
|
|
61
|
-
}
|
|
62
|
-
]
|
|
55
|
+
choices: [{ index: 0, delta: {}, finish_reason: 'tool_calls' }],
|
|
63
56
|
}) + 'data: [DONE]\n\n';
|
|
64
57
|
}
|
|
65
58
|
function textResponse(text, id = 'deadline-final') {
|
|
66
59
|
return sse({
|
|
67
|
-
id,
|
|
68
|
-
object: 'chat.completion.chunk',
|
|
69
|
-
created: 1,
|
|
60
|
+
id, object: 'chat.completion.chunk', created: 1,
|
|
70
61
|
model: 'synthetic-deadline-model',
|
|
71
|
-
choices: [
|
|
72
|
-
{
|
|
73
|
-
index: 0,
|
|
74
|
-
delta: {
|
|
75
|
-
role: 'assistant',
|
|
76
|
-
content: text
|
|
77
|
-
},
|
|
78
|
-
finish_reason: null
|
|
79
|
-
}
|
|
80
|
-
]
|
|
62
|
+
choices: [{ index: 0, delta: { role: 'assistant', content: text }, finish_reason: null }],
|
|
81
63
|
}) + sse({
|
|
82
|
-
id: `${id}-finish`,
|
|
83
|
-
|
|
84
|
-
created: 1,
|
|
85
|
-
model: 'synthetic-deadline-model',
|
|
86
|
-
choices: [
|
|
87
|
-
{
|
|
88
|
-
index: 0,
|
|
89
|
-
delta: {},
|
|
90
|
-
finish_reason: 'stop'
|
|
91
|
-
}
|
|
92
|
-
]
|
|
64
|
+
id: `${id}-finish`, object: 'chat.completion.chunk', created: 1,
|
|
65
|
+
model: 'synthetic-deadline-model', choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
|
|
93
66
|
}) + 'data: [DONE]\n\n';
|
|
94
67
|
}
|
|
95
68
|
async function startRelay() {
|
|
96
69
|
const bodies = [];
|
|
97
70
|
const plannerBodies = [];
|
|
98
|
-
const server = createServer((req, res)=>{
|
|
71
|
+
const server = createServer((req, res) => {
|
|
99
72
|
if (req.method !== 'POST' || !req.url?.endsWith('/chat/completions')) {
|
|
100
73
|
res.writeHead(404).end('not found');
|
|
101
74
|
return;
|
|
102
75
|
}
|
|
103
76
|
const chunks = [];
|
|
104
|
-
req.on('data',
|
|
105
|
-
req.on('end', ()=>{
|
|
77
|
+
req.on('data', chunk => chunks.push(Buffer.from(chunk)));
|
|
78
|
+
req.on('end', () => {
|
|
106
79
|
let body;
|
|
107
80
|
try {
|
|
108
81
|
body = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
109
|
-
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
110
84
|
body = {};
|
|
111
85
|
}
|
|
112
86
|
bodies.push(body);
|
|
113
|
-
res.writeHead(200, {
|
|
114
|
-
'content-type': 'text/event-stream',
|
|
115
|
-
'cache-control': 'no-cache'
|
|
116
|
-
});
|
|
87
|
+
res.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' });
|
|
117
88
|
if (toolNames(body).includes(TOOL)) {
|
|
118
89
|
plannerBodies.push(body);
|
|
119
90
|
const plannerIndex = plannerBodies.length;
|
|
120
|
-
|
|
121
|
-
|
|
91
|
+
// issue #205:已交接判定只认真实 role=tool 消息(persona (21) 的
|
|
92
|
+
// TURN_DEADLINE_HANDOFF 字面量也在 system 文本里,整包扫描会首轮误判
|
|
93
|
+
// 已交接 → 永不派发工具 → handoff 语义测试退化为纯文本收尾)。
|
|
94
|
+
const realToolMessages = (body.messages ?? []).filter(message => message.role === 'tool');
|
|
95
|
+
const alreadyHandedOff = realToolMessages.some(message => JSON.stringify(message).includes(HANDOFF));
|
|
96
|
+
// 首个 planner 响应拖过硬阈:首个工具派发必然越过 wall-clock 边界。
|
|
97
|
+
// handoff 发生后,后续 planner 请求一律回 text-only final,收敛回路。
|
|
122
98
|
const stall = !alreadyHandedOff && plannerIndex === 1 ? RELAY_STALL_MS : 0;
|
|
123
|
-
setTimeout(()=>{
|
|
99
|
+
setTimeout(() => {
|
|
124
100
|
if (!alreadyHandedOff && plannerIndex === 1) {
|
|
125
101
|
res.end(toolResponse(String(plannerIndex)));
|
|
126
|
-
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
127
104
|
res.end(textResponse('deadline E2E final answer'));
|
|
128
105
|
}
|
|
129
106
|
}, stall);
|
|
130
|
-
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Session-title and other auxiliary calls deliberately carry no tool
|
|
110
|
+
// schemas. Keep them out of the planner-call budget and answer text.
|
|
131
111
|
res.end(textResponse('deadline E2E final answer', 'deadline-auxiliary'));
|
|
132
112
|
}
|
|
133
113
|
});
|
|
134
114
|
});
|
|
135
|
-
await new Promise(
|
|
115
|
+
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
136
116
|
return {
|
|
137
117
|
port: server.address().port,
|
|
138
118
|
bodies,
|
|
139
119
|
plannerBodies,
|
|
140
|
-
close: ()=>new Promise(
|
|
120
|
+
close: () => new Promise(resolve => server.close(() => resolve())),
|
|
141
121
|
};
|
|
142
122
|
}
|
|
143
123
|
function allToolMessages(bodies) {
|
|
144
|
-
return bodies.flatMap(
|
|
124
|
+
return bodies.flatMap(body => (body.messages ?? []).filter(message => message.role === 'tool'));
|
|
145
125
|
}
|
|
146
126
|
function toolNames(body) {
|
|
147
|
-
return (body.tools ?? []).map(
|
|
127
|
+
return (body.tools ?? []).map(tool => {
|
|
148
128
|
const fn = tool.function;
|
|
149
129
|
return String(fn?.name ?? tool.name ?? '');
|
|
150
130
|
}).filter(Boolean);
|
|
151
131
|
}
|
|
152
132
|
async function main() {
|
|
153
|
-
for (const file of [
|
|
154
|
-
'dist/src/index.js',
|
|
155
|
-
'dist/capabilities/artifacts.js'
|
|
156
|
-
]){
|
|
133
|
+
for (const file of ['dist/src/index.js', 'dist/capabilities/artifacts.js']) {
|
|
157
134
|
assert.ok(existsSync(join(ROOT, file)), `missing ${file}; run node scripts/build-dist.mjs first`);
|
|
158
135
|
}
|
|
159
136
|
const relay = await startRelay();
|
|
160
137
|
const dshHome = mkdtempSync(join(tmpdir(), 'gotry-deadline-dsh-home-'));
|
|
161
138
|
const childCwd = mkdtempSync(join(tmpdir(), 'gotry-deadline-cwd-'));
|
|
139
|
+
// 巡检状态纪律:handoff 工单只落隔离根(source 模式 dsh cwd 是创始人真实
|
|
140
|
+
// 数据目录 ts/dsh-runtime,绝不让 E2E 往那里写)。
|
|
162
141
|
const handoffRoot = mkdtempSync(join(tmpdir(), 'gotry-deadline-handoff-'));
|
|
163
142
|
let exitCode = null;
|
|
164
143
|
let output = '';
|
|
165
144
|
const configuredBin = process.env.GOTRY_DEADLINE_E2E_BIN;
|
|
166
145
|
assert.ok(configuredBin && existsSync(configuredBin), 'GOTRY_DEADLINE_E2E_BIN must point to the clean installed-package binary');
|
|
167
146
|
try {
|
|
168
|
-
const executableArgs = [
|
|
169
|
-
|
|
170
|
-
];
|
|
171
|
-
const childEnv = {
|
|
172
|
-
...process.env
|
|
173
|
-
};
|
|
147
|
+
const executableArgs = [DEEP_MESSAGE];
|
|
148
|
+
const childEnv = { ...process.env };
|
|
174
149
|
childEnv.DSH_HOME = dshHome;
|
|
150
|
+
// 可选宿主插件(calendar)挂载与否由 setup 状态面(~/.gotry/calendar.json)决定,
|
|
151
|
+
// 不吃 env(D-9 founder 纠偏)——E2E 隔离手段=HOME 指到临时目录(os.homedir()
|
|
152
|
+
// 尊重 $HOME),子进程看不到真实机器的 setup 态;dsh 配置面已由 DSH_HOME 单独隔离。
|
|
175
153
|
childEnv.HOME = dshHome;
|
|
176
154
|
childEnv.LLM_API_KEY = 'synthetic-e2e-key';
|
|
177
155
|
childEnv.LLM_BASE_URL = 'http://127.0.0.1:' + relay.port + '/v1';
|
|
@@ -185,60 +163,57 @@ async function main() {
|
|
|
185
163
|
const child = spawn(configuredBin, executableArgs, {
|
|
186
164
|
cwd: childCwd,
|
|
187
165
|
env: childEnv,
|
|
188
|
-
stdio: [
|
|
189
|
-
'ignore',
|
|
190
|
-
'pipe',
|
|
191
|
-
'pipe'
|
|
192
|
-
]
|
|
193
|
-
});
|
|
194
|
-
child.stdout.on('data', (chunk)=>{
|
|
195
|
-
output += chunk.toString();
|
|
166
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
196
167
|
});
|
|
197
|
-
child.
|
|
198
|
-
|
|
168
|
+
child.stdout.on('data', chunk => { output += chunk.toString(); });
|
|
169
|
+
child.stderr.on('data', chunk => { output += chunk.toString(); });
|
|
170
|
+
exitCode = await new Promise(resolve => {
|
|
171
|
+
const timer = setTimeout(() => { child.kill('SIGKILL'); resolve(null); }, TIMEOUT_MS);
|
|
172
|
+
child.once('exit', code => { clearTimeout(timer); resolve(code); });
|
|
199
173
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
clearTimeout(timer);
|
|
207
|
-
resolve(code);
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
} finally{
|
|
211
|
-
await new Promise((resolve)=>setTimeout(resolve, 200));
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
// relay 故意不在此关闭:收集闭环段还要以同一 relay 做模型端点。
|
|
177
|
+
// Give the spawned binary a brief moment to release its temp files
|
|
178
|
+
// before we recursively remove the tmpdir.
|
|
179
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
212
180
|
}
|
|
213
181
|
assert.equal(exitCode, 0, `headless exit=${exitCode}; output tail=${output.slice(-1200)}`);
|
|
214
182
|
assert.ok(relay.plannerBodies.length >= 1, `expected at least one tool-enabled planner request, got ${relay.plannerBodies.length}; output tail=${output.slice(-12_000)}`);
|
|
183
|
+
// 首个工具派发越过硬阈:必须得到 handoff 语义的结构化拒绝,且没有任何
|
|
184
|
+
// 工具 body 真正执行。
|
|
215
185
|
const toolMessages = allToolMessages(relay.bodies);
|
|
216
186
|
const toolMessageDiagnostic = JSON.stringify(toolMessages).slice(-12_000);
|
|
217
|
-
const handoffResults = toolMessages.filter(
|
|
218
|
-
const successfulResults = toolMessages.filter(
|
|
187
|
+
const handoffResults = toolMessages.filter(message => JSON.stringify(message).includes(HANDOFF));
|
|
188
|
+
const successfulResults = toolMessages.filter(message => !JSON.stringify(message).includes(HANDOFF));
|
|
219
189
|
assert.ok(handoffResults.length >= 1, `expected at least one handoff result; messages=${toolMessageDiagnostic}`);
|
|
220
190
|
assert.equal(successfulResults.length, 0, `no tool body should run past the hard deadline; messages=${toolMessageDiagnostic}`);
|
|
221
191
|
assert.match(JSON.stringify(handoffResults[0]), /th-/, 'handoff result carries the ticket id');
|
|
192
|
+
// handoff 工单已落隔离根,字段完整(含用户原文与 ETA 承诺)。
|
|
222
193
|
const ticketDir = join(handoffRoot, 'gotry-state', 'turn-handoffs');
|
|
223
194
|
assert.ok(existsSync(ticketDir), `ticket dir missing: ${ticketDir}`);
|
|
224
|
-
const ticketFiles = readdirSync(ticketDir).filter(
|
|
195
|
+
const ticketFiles = readdirSync(ticketDir).filter(name => name.endsWith('.json'));
|
|
225
196
|
assert.equal(ticketFiles.length, 1, `expected exactly one handoff ticket, got ${ticketFiles.join(', ')}`);
|
|
226
197
|
const ticket = JSON.parse(readFileSync(join(ticketDir, ticketFiles[0]), 'utf8'));
|
|
227
198
|
assert.equal(ticket['schema'], HANDOFF_SCHEMA);
|
|
228
199
|
assert.equal(ticket['status'], 'open');
|
|
229
200
|
assert.ok(String(ticket['userMessage']).includes('婚礼'), 'ticket carries the verbatim deep-planning ask');
|
|
230
201
|
assert.ok(String(ticket['etaLabel']).includes('约 1 小时'));
|
|
202
|
+
// 回路收敛:最终请求不带任何继承工具 schema,二进制输出 final。
|
|
231
203
|
const finalRequest = relay.bodies.at(-1);
|
|
232
204
|
const finalNames = toolNames(finalRequest);
|
|
233
205
|
assert.ok(!finalNames.includes(TOOL), `final request inherited GoTry tool: ${finalNames.join(', ')}`);
|
|
234
206
|
assert.match(output, /deadline E2E final answer/);
|
|
207
|
+
// ---- 收集闭环:collector 以真打包二进制为 planner 回收这单工单。------
|
|
208
|
+
// 子会话(GOTRY_HANDOFF_CHILD=1)带满工具面打到 relay;relay 的全局
|
|
209
|
+
// plannerIndex 已 >1,立即回 text-only final → 子会话 converge 退出,
|
|
210
|
+
// collector 把最终答复结算为交付物。工单 open→settled,交付物可复访。
|
|
235
211
|
{
|
|
236
212
|
const ticketId = String(ticket['id']);
|
|
237
213
|
const collector = spawn(process.execPath, [
|
|
238
214
|
join(TS_DIR, 'node_modules', 'tsx', 'dist', 'cli.mjs'),
|
|
239
215
|
join(TS_DIR, 'scripts', 'turn-handoff-collect.ts'),
|
|
240
|
-
ticketId,
|
|
241
|
-
handoffRoot
|
|
216
|
+
ticketId, handoffRoot,
|
|
242
217
|
], {
|
|
243
218
|
cwd: TS_DIR,
|
|
244
219
|
env: {
|
|
@@ -247,31 +222,17 @@ async function main() {
|
|
|
247
222
|
LLM_API_KEY: 'synthetic-e2e-key',
|
|
248
223
|
LLM_BASE_URL: 'http://127.0.0.1:' + relay.port + '/v1',
|
|
249
224
|
LLM_MODEL: 'synthetic-deadline-model',
|
|
250
|
-
GOTRY_LOCALE: 'zh-CN'
|
|
225
|
+
GOTRY_LOCALE: 'zh-CN',
|
|
251
226
|
},
|
|
252
|
-
stdio: [
|
|
253
|
-
'ignore',
|
|
254
|
-
'pipe',
|
|
255
|
-
'pipe'
|
|
256
|
-
]
|
|
227
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
257
228
|
});
|
|
258
229
|
let collectorOut = '';
|
|
259
230
|
let collectorErr = '';
|
|
260
|
-
collector.stdout.on('data',
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
});
|
|
266
|
-
const collectorCode = await new Promise((resolve)=>{
|
|
267
|
-
const timer = setTimeout(()=>{
|
|
268
|
-
collector.kill('SIGKILL');
|
|
269
|
-
resolve(null);
|
|
270
|
-
}, 90_000);
|
|
271
|
-
collector.once('exit', (code)=>{
|
|
272
|
-
clearTimeout(timer);
|
|
273
|
-
resolve(code);
|
|
274
|
-
});
|
|
231
|
+
collector.stdout.on('data', chunk => { collectorOut += chunk.toString(); });
|
|
232
|
+
collector.stderr.on('data', chunk => { collectorErr += chunk.toString(); });
|
|
233
|
+
const collectorCode = await new Promise(resolve => {
|
|
234
|
+
const timer = setTimeout(() => { collector.kill('SIGKILL'); resolve(null); }, 90_000);
|
|
235
|
+
collector.once('exit', code => { clearTimeout(timer); resolve(code); });
|
|
275
236
|
});
|
|
276
237
|
assert.equal(collectorCode, 0, `collector exit=${collectorCode}; stderr tail=${collectorErr.slice(-800)}; stdout tail=${collectorOut.slice(-400)}`);
|
|
277
238
|
const terminal = JSON.parse(collectorOut.trim().split('\n').at(-1));
|
|
@@ -286,20 +247,8 @@ async function main() {
|
|
|
286
247
|
}
|
|
287
248
|
console.log(`agent turn deadline E2E: OK (exit=${exitCode}, plannerRequests=${relay.plannerBodies.length}, handoffResults=${handoffResults.length}, ticket=${ticketFiles[0]}, collected=settled)`);
|
|
288
249
|
await relay.close();
|
|
289
|
-
rmSync(dshHome, {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
});
|
|
293
|
-
rmSync(childCwd, {
|
|
294
|
-
recursive: true,
|
|
295
|
-
force: true
|
|
296
|
-
});
|
|
297
|
-
rmSync(handoffRoot, {
|
|
298
|
-
recursive: true,
|
|
299
|
-
force: true
|
|
300
|
-
});
|
|
250
|
+
rmSync(dshHome, { recursive: true, force: true });
|
|
251
|
+
rmSync(childCwd, { recursive: true, force: true });
|
|
252
|
+
rmSync(handoffRoot, { recursive: true, force: true });
|
|
301
253
|
}
|
|
302
254
|
await main();
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
//# sourceURL=ts/scripts/agent-planning-turn-deadline-e2e.ts
|