@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
|
@@ -2,221 +2,137 @@ import assert from 'node:assert/strict';
|
|
|
2
2
|
import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import { installTurnDeadline, TURN_DEADLINE_EXHAUSTED, TURN_DEADLINE_HANDOFF, TURN_HANDOFF_SCHEMA, writeTurnHandoffTicket } from '../src/turn-deadline.js';
|
|
6
|
-
const success = ()=>({
|
|
7
|
-
isError: false,
|
|
8
|
-
value: null,
|
|
9
|
-
content: []
|
|
10
|
-
});
|
|
5
|
+
import { installTurnDeadline, TURN_DEADLINE_EXHAUSTED, TURN_DEADLINE_HANDOFF, TURN_HANDOFF_SCHEMA, writeTurnHandoffTicket, } from '../src/turn-deadline.js';
|
|
6
|
+
const success = () => ({ isError: false, value: null, content: [] });
|
|
11
7
|
const handlers = new Map();
|
|
12
8
|
const restricted = [];
|
|
13
9
|
const lifted = [];
|
|
14
|
-
const makeAgent = (id)=>({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return ()=>lifted.push(id);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
10
|
+
const makeAgent = (id) => ({
|
|
11
|
+
id,
|
|
12
|
+
ctx: {
|
|
13
|
+
tools: {
|
|
14
|
+
restrict(filter) {
|
|
15
|
+
restricted.push({ agentId: id, deny: [...filter.deny] });
|
|
16
|
+
return () => lifted.push(id);
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
30
21
|
const ctx = {
|
|
31
22
|
tools: {
|
|
32
|
-
schemas: ()=>[
|
|
33
|
-
{
|
|
34
|
-
name: 'gotry_alpha'
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
name: 'gotry_beta'
|
|
38
|
-
}
|
|
39
|
-
]
|
|
23
|
+
schemas: () => [{ name: 'gotry_alpha' }, { name: 'gotry_beta' }],
|
|
40
24
|
},
|
|
41
|
-
on
|
|
25
|
+
on(event, listener) {
|
|
42
26
|
const bucket = handlers.get(event) ?? [];
|
|
43
27
|
bucket.push(listener);
|
|
44
28
|
handlers.set(event, bucket);
|
|
45
|
-
return ()=>{};
|
|
46
|
-
}
|
|
29
|
+
return () => { };
|
|
30
|
+
},
|
|
47
31
|
};
|
|
32
|
+
// Product-path opt-out: `enabled: false` must install nothing.
|
|
48
33
|
const productCtx = {
|
|
49
|
-
tools: {
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
on (event) {
|
|
34
|
+
tools: { schemas: () => [] },
|
|
35
|
+
on(event) {
|
|
53
36
|
throw new Error(`opt-out path must not subscribe to ${event}`);
|
|
54
|
-
}
|
|
37
|
+
},
|
|
55
38
|
};
|
|
56
|
-
installTurnDeadline(productCtx, {
|
|
57
|
-
|
|
58
|
-
});
|
|
59
|
-
const clock = (()=>{
|
|
39
|
+
installTurnDeadline(productCtx, { enabled: false });
|
|
40
|
+
const clock = (() => {
|
|
60
41
|
let t = 1_000_000;
|
|
61
|
-
return {
|
|
62
|
-
now: ()=>t,
|
|
63
|
-
advance: (ms)=>{
|
|
64
|
-
t += ms;
|
|
65
|
-
}
|
|
66
|
-
};
|
|
42
|
+
return { now: () => t, advance: (ms) => { t += ms; } };
|
|
67
43
|
})();
|
|
68
44
|
const handoffRoot = mkdtempSync(join(tmpdir(), 'gotry-turn-handoff-tests-'));
|
|
69
|
-
installTurnDeadline(ctx, {
|
|
70
|
-
stateRoot: handoffRoot,
|
|
71
|
-
now: clock.now
|
|
72
|
-
});
|
|
45
|
+
installTurnDeadline(ctx, { stateRoot: handoffRoot, now: clock.now });
|
|
73
46
|
const execute = handlers.get('tools/execute')?.[0];
|
|
74
47
|
const postExecute = handlers.get('tools/post-execute')?.[0];
|
|
75
48
|
const sessionEvent = handlers.get('session/event')?.[0];
|
|
76
49
|
const sessionDisposed = handlers.get('session/disposed')?.[0];
|
|
77
50
|
assert.ok(execute && postExecute && sessionEvent && sessionDisposed, 'all Cordis boundary hooks register');
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
data: {
|
|
83
|
-
source: {
|
|
84
|
-
kind
|
|
85
|
-
},
|
|
86
|
-
content: [
|
|
87
|
-
{
|
|
88
|
-
type: 'text',
|
|
89
|
-
text
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
const turnEvent = (id, type)=>sessionEvent({
|
|
95
|
-
id
|
|
96
|
-
}, {
|
|
97
|
-
type
|
|
98
|
-
});
|
|
51
|
+
// dsh 事件载荷在 event.data 下(与 benchmark-agent-conformance 同型)。
|
|
52
|
+
const userMessage = (id, text, kind = 'user') => sessionEvent({ id }, { type: 'user/message', data: { source: { kind }, content: [{ type: 'text', text }] } });
|
|
53
|
+
const turnEvent = (id, type) => sessionEvent({ id }, { type });
|
|
54
|
+
// Agent-less calls are programmatic control-plane calls, not planner spend.
|
|
99
55
|
{
|
|
100
56
|
let directBodies = 0;
|
|
101
|
-
for(let i = 0; i < 5; i++){
|
|
102
|
-
const result = await execute({
|
|
103
|
-
token: Symbol(`direct-${i}`)
|
|
104
|
-
}, async ()=>{
|
|
105
|
-
directBodies++;
|
|
106
|
-
return success();
|
|
107
|
-
});
|
|
57
|
+
for (let i = 0; i < 5; i++) {
|
|
58
|
+
const result = await execute({ token: Symbol(`direct-${i}`) }, async () => { directBodies++; return success(); });
|
|
108
59
|
assert.equal(result.isError, false);
|
|
109
60
|
}
|
|
110
61
|
assert.equal(directBodies, 5);
|
|
111
|
-
}
|
|
62
|
+
}
|
|
63
|
+
// ---- converge 路径:sync-planning 消息,软提示 + 硬阈结构化拒绝 ----------------
|
|
64
|
+
{
|
|
112
65
|
const agent = makeAgent('agent-converge');
|
|
113
66
|
turnEvent(agent.id, 'turn/start');
|
|
114
67
|
userMessage(agent.id, '帮我看看10.1去杭州的高铁票');
|
|
115
68
|
{
|
|
116
|
-
const exec = {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
};
|
|
120
|
-
const result = await execute(exec, async ()=>success());
|
|
121
|
-
const post = await postExecute(exec, result, async ()=>({
|
|
122
|
-
kind: 'accept'
|
|
123
|
-
}));
|
|
69
|
+
const exec = { token: Symbol('conv-1'), agent };
|
|
70
|
+
const result = await execute(exec, async () => success());
|
|
71
|
+
const post = await postExecute(exec, result, async () => ({ kind: 'accept' }));
|
|
124
72
|
assert.equal(result.isError, false);
|
|
125
73
|
assert.equal((post.additionalContexts ?? []).length, 0, 'no convergence context before soft');
|
|
126
74
|
assert.equal(restricted.length, 0);
|
|
127
75
|
}
|
|
76
|
+
// 推进超过软阈(sync-planning 300s):post-execute 注入 TURN_DEADLINE_SOFT
|
|
128
77
|
clock.advance(300_001);
|
|
129
78
|
{
|
|
130
|
-
const exec = {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const result = await execute(exec, async ()=>success());
|
|
135
|
-
const post = await postExecute(exec, result, async ()=>({
|
|
136
|
-
kind: 'accept'
|
|
137
|
-
}));
|
|
138
|
-
const contextText = post.additionalContexts?.flatMap((item)=>item.content ?? []).map((item)=>item.text ?? '').join('\n') ?? '';
|
|
79
|
+
const exec = { token: Symbol('conv-2'), agent };
|
|
80
|
+
const result = await execute(exec, async () => success());
|
|
81
|
+
const post = await postExecute(exec, result, async () => ({ kind: 'accept' }));
|
|
82
|
+
const contextText = post.additionalContexts?.flatMap(item => item.content ?? []).map(item => item.text ?? '').join('\n') ?? '';
|
|
139
83
|
assert.ok(contextText.includes('TURN_DEADLINE_SOFT'), 'soft context after crossing softMs');
|
|
140
84
|
assert.ok(contextText.includes('final answer'), 'converge soft text asks for a final answer');
|
|
141
85
|
}
|
|
86
|
+
// 推进超过硬阈(600s):结构化拒绝 + 同步抑制 schema,不落任何工单
|
|
142
87
|
clock.advance(300_000);
|
|
143
88
|
{
|
|
144
|
-
const exec = {
|
|
145
|
-
token: Symbol('conv-3'),
|
|
146
|
-
agent
|
|
147
|
-
};
|
|
89
|
+
const exec = { token: Symbol('conv-3'), agent };
|
|
148
90
|
let bodyRan = false;
|
|
149
|
-
const result = await execute(exec, async ()=>{
|
|
150
|
-
bodyRan = true;
|
|
151
|
-
return success();
|
|
152
|
-
});
|
|
91
|
+
const result = await execute(exec, async () => { bodyRan = true; return success(); });
|
|
153
92
|
assert.equal(bodyRan, false);
|
|
154
93
|
assert.equal(result.isError, true);
|
|
155
|
-
assert.deepEqual(result.error?.info, {
|
|
156
|
-
name: 'TurnDeadlineError',
|
|
157
|
-
code: TURN_DEADLINE_EXHAUSTED
|
|
158
|
-
});
|
|
94
|
+
assert.deepEqual(result.error?.info, { name: 'TurnDeadlineError', code: TURN_DEADLINE_EXHAUSTED });
|
|
159
95
|
assert.match(result.content[0]?.text ?? '', /TURN_DEADLINE_EXHAUSTED/);
|
|
160
96
|
}
|
|
161
|
-
assert.deepEqual(restricted.at(-1), {
|
|
162
|
-
agentId: agent.id,
|
|
163
|
-
deny: [
|
|
164
|
-
'gotry_alpha',
|
|
165
|
-
'gotry_beta'
|
|
166
|
-
]
|
|
167
|
-
});
|
|
97
|
+
assert.deepEqual(restricted.at(-1), { agentId: agent.id, deny: ['gotry_alpha', 'gotry_beta'] });
|
|
168
98
|
const convergeTicketDir = join(handoffRoot, 'gotry-state', 'turn-handoffs');
|
|
169
99
|
assert.equal(existsSync(convergeTicketDir) ? readdirSync(convergeTicketDir).length : 0, 0, 'converge writes no ticket');
|
|
170
100
|
turnEvent(agent.id, 'turn/end');
|
|
171
101
|
assert.equal(lifted.at(-1), agent.id);
|
|
172
|
-
}
|
|
102
|
+
}
|
|
103
|
+
// ---- handoff 路径:deep-planning 消息(失败轨迹原文)→ 落单转后台 -----------
|
|
104
|
+
{
|
|
173
105
|
const agent = makeAgent('agent-handoff');
|
|
174
106
|
turnEvent(agent.id, 'turn/start');
|
|
175
|
-
const deepMessage = '2026年我还有6天IRW额度 ,我准备再请几天假,在国内待个十几天。'
|
|
107
|
+
const deepMessage = '2026年我还有6天IRW额度 ,我准备再请几天假,在国内待个十几天。'
|
|
108
|
+
+ '其中10.3要去湖南衡阳参加同学婚礼。其他我没有特别的要求,请根据我的实际情况,偏好,外部环境等因素,给我安排行程';
|
|
176
109
|
userMessage(agent.id, deepMessage);
|
|
110
|
+
// 软阈(deep 120s):提示语义是「收尾摸底、即将转后台」
|
|
177
111
|
clock.advance(120_001);
|
|
178
112
|
{
|
|
179
|
-
const exec = {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const result = await execute(exec, async ()=>success());
|
|
184
|
-
const post = await postExecute(exec, result, async ()=>({
|
|
185
|
-
kind: 'accept'
|
|
186
|
-
}));
|
|
187
|
-
const contextText = post.additionalContexts?.flatMap((item)=>item.content ?? []).map((item)=>item.text ?? '').join('\n') ?? '';
|
|
113
|
+
const exec = { token: Symbol('hand-1'), agent };
|
|
114
|
+
const result = await execute(exec, async () => success());
|
|
115
|
+
const post = await postExecute(exec, result, async () => ({ kind: 'accept' }));
|
|
116
|
+
const contextText = post.additionalContexts?.flatMap(item => item.content ?? []).map(item => item.text ?? '').join('\n') ?? '';
|
|
188
117
|
assert.ok(contextText.includes('background planning'), 'handoff soft text announces the handoff');
|
|
189
118
|
assert.equal(result.isError, false);
|
|
190
119
|
}
|
|
120
|
+
// 硬阈(240s):TURN_DEADLINE_HANDOFF 结构化结果 + 工单落盘
|
|
191
121
|
clock.advance(120_000);
|
|
192
122
|
{
|
|
193
|
-
const exec = {
|
|
194
|
-
token: Symbol('hand-2'),
|
|
195
|
-
agent
|
|
196
|
-
};
|
|
123
|
+
const exec = { token: Symbol('hand-2'), agent };
|
|
197
124
|
let bodyRan = false;
|
|
198
|
-
const result = await execute(exec, async ()=>{
|
|
199
|
-
bodyRan = true;
|
|
200
|
-
return success();
|
|
201
|
-
});
|
|
125
|
+
const result = await execute(exec, async () => { bodyRan = true; return success(); });
|
|
202
126
|
assert.equal(bodyRan, false);
|
|
203
127
|
assert.equal(result.isError, true);
|
|
204
|
-
assert.deepEqual(result.error?.info, {
|
|
205
|
-
name: 'TurnDeadlineHandoff',
|
|
206
|
-
code: TURN_DEADLINE_HANDOFF
|
|
207
|
-
});
|
|
128
|
+
assert.deepEqual(result.error?.info, { name: 'TurnDeadlineHandoff', code: TURN_DEADLINE_HANDOFF });
|
|
208
129
|
const text = result.content[0]?.text ?? '';
|
|
209
130
|
assert.match(text, /TURN_DEADLINE_HANDOFF/);
|
|
210
131
|
assert.match(text, /th-/, 'result names the persisted ticket id');
|
|
211
132
|
assert.match(text, /约 1 小时/, 'ETA label mirrors the S5 promise');
|
|
212
133
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
deny: [
|
|
216
|
-
'gotry_alpha',
|
|
217
|
-
'gotry_beta'
|
|
218
|
-
]
|
|
219
|
-
});
|
|
134
|
+
// 同步抑制已生效
|
|
135
|
+
assert.deepEqual(restricted.at(-1), { agentId: agent.id, deny: ['gotry_alpha', 'gotry_beta'] });
|
|
220
136
|
const tickets = readdirSync(join(handoffRoot, 'gotry-state', 'turn-handoffs'));
|
|
221
137
|
assert.equal(tickets.length, 1, 'exactly one handoff ticket');
|
|
222
138
|
const ticket = JSON.parse(readFileSync(join(handoffRoot, 'gotry-state', 'turn-handoffs', tickets[0]), 'utf8'));
|
|
@@ -225,38 +141,36 @@ const turnEvent = (id, type)=>sessionEvent({
|
|
|
225
141
|
assert.equal(ticket.userMessage, deepMessage, 'ticket carries the verbatim user ask');
|
|
226
142
|
assert.ok(ticket.requestedAt);
|
|
227
143
|
assert.equal(ticket.etaLabel, '约 1 小时');
|
|
144
|
+
// 新 user 消息 = 新预算:同 agent 下一轮 quick 消息恢复放行
|
|
228
145
|
turnEvent(agent.id, 'turn/end');
|
|
229
146
|
userMessage(agent.id, '你好');
|
|
230
147
|
{
|
|
231
|
-
const result = await execute({
|
|
232
|
-
token: Symbol('hand-3'),
|
|
233
|
-
agent
|
|
234
|
-
}, async ()=>success());
|
|
148
|
+
const result = await execute({ token: Symbol('hand-3'), agent }, async () => success());
|
|
235
149
|
assert.equal(result.isError, false);
|
|
236
150
|
}
|
|
237
151
|
turnEvent(agent.id, 'turn/end');
|
|
238
152
|
assert.equal(readdirSync(join(handoffRoot, 'gotry-state', 'turn-handoffs')).length, 1, 'no extra tickets');
|
|
239
|
-
}
|
|
153
|
+
}
|
|
154
|
+
// ---- 路由输入纪律:plugin 注入的 user/message 不参与路由 --------------------
|
|
155
|
+
{
|
|
240
156
|
const agent = makeAgent('agent-plugin-msg');
|
|
241
157
|
turnEvent(agent.id, 'turn/start');
|
|
242
158
|
userMessage(agent.id, '你好');
|
|
159
|
+
// plugin 注入的深规划文本不得翻转预算
|
|
243
160
|
userMessage(agent.id, deepPlanningNoise(), 'plugin');
|
|
244
161
|
clock.advance(1_000_000);
|
|
245
162
|
{
|
|
246
|
-
const exec = {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
};
|
|
250
|
-
const result = await execute(exec, async ()=>success());
|
|
251
|
-
assert.deepEqual(result.error?.info, {
|
|
252
|
-
name: 'TurnDeadlineError',
|
|
253
|
-
code: TURN_DEADLINE_EXHAUSTED
|
|
254
|
-
});
|
|
163
|
+
const exec = { token: Symbol('plug-1'), agent };
|
|
164
|
+
const result = await execute(exec, async () => success());
|
|
165
|
+
// quick 硬阈 180s 已被跨过 → converge 拒绝(而非 handoff):证明路由未被 plugin 消息改写
|
|
166
|
+
assert.deepEqual(result.error?.info, { name: 'TurnDeadlineError', code: TURN_DEADLINE_EXHAUSTED });
|
|
255
167
|
}
|
|
256
168
|
turnEvent(agent.id, 'turn/end');
|
|
257
|
-
}
|
|
169
|
+
}
|
|
170
|
+
function deepPlanningNoise() {
|
|
258
171
|
return '系统提醒样例:10.3 婚礼 IRW 请假 十几天 安排行程——这是插件注入,不该参与路由';
|
|
259
172
|
}
|
|
173
|
+
// ---- 工单写入器(独立契约:原子写 + 目录形态) ------------------------------
|
|
260
174
|
{
|
|
261
175
|
const root = mkdtempSync(join(tmpdir(), 'gotry-turn-handoff-writer-'));
|
|
262
176
|
const ticket = await writeTurnHandoffTicket(root, '短消息');
|
|
@@ -264,18 +178,8 @@ const turnEvent = (id, type)=>sessionEvent({
|
|
|
264
178
|
assert.equal(readdirSync(dir).length, 1);
|
|
265
179
|
const loaded = JSON.parse(readFileSync(join(dir, `${ticket.id}.json`), 'utf8'));
|
|
266
180
|
assert.equal(loaded.userMessage, '短消息');
|
|
267
|
-
rmSync(root, {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}sessionDisposed({
|
|
272
|
-
id: 'agent-handoff'
|
|
273
|
-
});
|
|
274
|
-
rmSync(handoffRoot, {
|
|
275
|
-
recursive: true,
|
|
276
|
-
force: true
|
|
277
|
-
});
|
|
181
|
+
rmSync(root, { recursive: true, force: true });
|
|
182
|
+
}
|
|
183
|
+
sessionDisposed({ id: 'agent-handoff' });
|
|
184
|
+
rmSync(handoffRoot, { recursive: true, force: true });
|
|
278
185
|
console.log('agent turn deadline tests: OK (routing→converge/handoff exits, ticket persistence, plugin-message discipline, lifecycle)');
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
//# sourceURL=ts/scripts/agent-planning-turn-deadline-tests.ts
|
|
@@ -1,54 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach 深度能力层测试(yt-dlp + gh,系统装了就调,没装降级):
|
|
3
|
+
* 1. yt-dlp:无论装没装,三值之一(found/not-installed/error)且不抛错
|
|
4
|
+
* 2. gh 搜索:gh 已装的环境真实搜 agent-reach;未装环境走 not-installed
|
|
5
|
+
* 3. 证据链标注含 [agent-reach:<bin>@
|
|
6
|
+
* 4. 超时降级
|
|
7
|
+
*
|
|
8
|
+
* 运行: cd ts && npx tsx scripts/agent-reach-deep-tests.ts
|
|
9
|
+
*/
|
|
1
10
|
import assert from 'node:assert/strict';
|
|
2
11
|
import { videoSubtitle, githubSearch } from '../capabilities/agent-reach-deep.js';
|
|
12
|
+
// 1. yt-dlp 三值
|
|
3
13
|
{
|
|
4
|
-
const r = await videoSubtitle({
|
|
5
|
-
|
|
6
|
-
timeoutMs: 15_000
|
|
7
|
-
});
|
|
8
|
-
assert.ok([
|
|
9
|
-
'found',
|
|
10
|
-
'not-installed',
|
|
11
|
-
'error',
|
|
12
|
-
'timeout'
|
|
13
|
-
].includes(r.verdict), `verdict 三值之一: ${r.verdict}`);
|
|
14
|
+
const r = await videoSubtitle({ url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', timeoutMs: 15_000 });
|
|
15
|
+
assert.ok(['found', 'not-installed', 'error', 'timeout'].includes(r.verdict), `verdict 三值之一: ${r.verdict}`);
|
|
14
16
|
assert.ok(r.evidence.includes('[agent-reach:yt-dlp@'), '证据链前缀');
|
|
15
17
|
console.log(`1. yt-dlp → ${r.verdict} (${r.latencyMs}ms) OK`);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
assert.ok([
|
|
22
|
-
'found',
|
|
23
|
-
'not-installed',
|
|
24
|
-
'error',
|
|
25
|
-
'timeout'
|
|
26
|
-
].includes(r.verdict));
|
|
18
|
+
}
|
|
19
|
+
// 2. gh 搜索(装了就真实搜,没装走 not-installed)
|
|
20
|
+
{
|
|
21
|
+
const r = await githubSearch({ query: 'agent-reach', limit: 3 });
|
|
22
|
+
assert.ok(['found', 'not-installed', 'error', 'timeout'].includes(r.verdict));
|
|
27
23
|
if (r.verdict === 'found') {
|
|
28
24
|
assert.ok((r.repos?.length ?? 0) > 0, 'found 应有 repos');
|
|
29
25
|
const top = r.repos[0];
|
|
30
26
|
console.log(`2. gh search → found (top: ${top.name} ★${top.stars}) OK`);
|
|
31
|
-
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
32
29
|
console.log(`2. gh search → ${r.verdict} (${r.stderr?.slice(0, 60)}) OK`);
|
|
33
30
|
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
31
|
+
}
|
|
32
|
+
// 3. 证据链格式
|
|
33
|
+
{
|
|
34
|
+
const r = await githubSearch({ query: 'hello' });
|
|
38
35
|
assert.match(r.evidence, /\[agent-reach:gh@/, 'gh 证据链');
|
|
39
36
|
console.log('3. 证据链格式 OK');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
assert.ok([
|
|
46
|
-
'timeout',
|
|
47
|
-
'error',
|
|
48
|
-
'not-installed'
|
|
49
|
-
].includes(r.verdict));
|
|
37
|
+
}
|
|
38
|
+
// 4. 超时降级(1ms timeout)
|
|
39
|
+
{
|
|
40
|
+
const r = await githubSearch({ query: 'hello', timeoutMs: 1 });
|
|
41
|
+
assert.ok(['timeout', 'error', 'not-installed'].includes(r.verdict));
|
|
50
42
|
console.log(`4. 超时 → ${r.verdict} OK`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
//# sourceURL=ts/scripts/agent-reach-deep-tests.ts
|
|
43
|
+
}
|
|
44
|
+
console.log('\nAGENT-REACH DEEP TESTS: 4/4 OK(yt-dlp/gh 可选工具,不装则降级)');
|
|
@@ -1,38 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach web 读取(readUrl 薄壳)测试:
|
|
3
|
+
* readUrl = URL 校验 + 委托上游 WebChannel.read(反射桥) + Title 提取,自身无网络实现。
|
|
4
|
+
* 上游真读已在 §15 wrapper 测试覆盖;本套只测薄壳行为:
|
|
5
|
+
* 1. 非法 URL(不带 http) → 拒绝,不抛错,降级返回(离线确定性)
|
|
6
|
+
* 2. 1ms 超时 → 桥被杀,降级 error(离线确定性)
|
|
7
|
+
* 3. live 读 example.com → 成功时断言 Title/证据链;网络边界允许降级(不抛错)
|
|
8
|
+
*
|
|
9
|
+
* 运行: cd ts && npx tsx scripts/agent-reach-tests.ts
|
|
10
|
+
*/
|
|
1
11
|
import assert from 'node:assert/strict';
|
|
2
12
|
import { readUrl } from '../capabilities/agent-reach.js';
|
|
13
|
+
// 1. 非法 URL(不带 scheme)
|
|
3
14
|
{
|
|
4
|
-
const r = await readUrl({
|
|
5
|
-
url: 'example.com'
|
|
6
|
-
});
|
|
15
|
+
const r = await readUrl({ url: 'example.com' });
|
|
7
16
|
assert.equal(r.ok, false);
|
|
8
17
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
9
18
|
assert.ok(r.evidence.includes('error'), 'evidence 带 error');
|
|
10
19
|
console.log('1. 非法 URL 拒绝 OK');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
});
|
|
20
|
+
}
|
|
21
|
+
// 2. 超时(1ms 杀掉反射桥进程)
|
|
22
|
+
{
|
|
23
|
+
const r = await readUrl({ url: 'https://example.com', timeoutMs: 1 });
|
|
16
24
|
assert.equal(r.ok, false);
|
|
17
25
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
18
26
|
assert.ok(r.latencyMs >= 0, '永不抛错');
|
|
19
27
|
console.log('2. 超时降级 OK');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
28
|
+
}
|
|
29
|
+
// 3. live 读 example.com(上游 Jina Reader;网络边界允许降级)
|
|
30
|
+
{
|
|
31
|
+
const r = await readUrl({ url: 'https://example.com', timeoutMs: 30_000 });
|
|
25
32
|
if (r.ok) {
|
|
26
33
|
assert.ok(r.evidence.includes('[agent-reach:web.read@'), '证据链');
|
|
27
34
|
assert.match(r.evidence, /\[agent-reach:web\.read@2\d{3}-\d{2}-\d{2}T/, '证据链带 ISO 时间戳');
|
|
28
35
|
assert.ok(typeof r.content === 'string' && r.content.length > 0, 'content 非空');
|
|
36
|
+
// live 内容会漂移(example.com 经 Jina 的 Title 曾从 Example Domain 变 Test Document),
|
|
37
|
+
// 断言结构(非空标题被提取)而非精确文案
|
|
29
38
|
assert.ok(typeof r.title === 'string' && r.title.length > 0, `Title 提取,实际 ${r.title}`);
|
|
30
39
|
console.log(`3. readUrl example.com → ok (title=${r.title}) OK`);
|
|
31
|
-
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
32
42
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
33
43
|
console.log(`3. readUrl example.com → 降级(${r.error?.slice(0, 60)})(网络边界,合法) OK`);
|
|
34
44
|
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//# sourceURL=ts/scripts/agent-reach-tests.ts
|
|
45
|
+
}
|
|
46
|
+
console.log('\nAGENT-REACH TESTS: 3/3 OK(readUrl 薄壳;上游真读见 wrapper 套)');
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach wrapper 测试(零渠道知识,全部走反射桥):
|
|
3
|
+
* 1. status: 真 agent-reach doctor 透传(via=agent-reach-cli)
|
|
4
|
+
* 2. web.read: 真读 example.com(上游 Jina Reader 后端)
|
|
5
|
+
* 3. v2ex.get_hot_topics: 上游 python 方法真调(网络边界允许降级)
|
|
6
|
+
* 4. xueqiu.get_stock_quote: 无 cookie → needs-setup 且 setup=上游 check() 原话
|
|
7
|
+
* 5. 未知渠道 → 自描述错误带回上游渠道清单
|
|
8
|
+
* 6. 未知方法 → 自描述错误带回上游方法签名清单
|
|
9
|
+
* 7. 永不抛错: 空 channel/method 降级
|
|
10
|
+
*
|
|
11
|
+
* 运行: cd ts && npx tsx scripts/agent-reach-wrapper-tests.ts
|
|
12
|
+
*/
|
|
1
13
|
import assert from 'node:assert/strict';
|
|
2
14
|
import { reach, reachStatus } from '../capabilities/agent-reach.js';
|
|
15
|
+
// 1. status(真 doctor 原样透传;agent-reach 未装时结构化 SKIP——真集成面设备绑定,
|
|
16
|
+
// 与 §17 skills-contract「有凭证真校验,离线 SKIP」同构;CI 装了则全跑 7 断言)
|
|
3
17
|
{
|
|
4
18
|
const st = await reachStatus(90_000);
|
|
5
19
|
if (!st.ok) {
|
|
@@ -10,74 +24,56 @@ import { reach, reachStatus } from '../capabilities/agent-reach.js';
|
|
|
10
24
|
assert.equal(st.via, 'agent-reach-cli');
|
|
11
25
|
assert.ok(st.output.length > 50, 'doctor 输出非空(上游原样)');
|
|
12
26
|
console.log(`1. status → doctor 透传 (${st.latencyMs}ms) OK`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
args: [
|
|
18
|
-
'https://example.com'
|
|
19
|
-
],
|
|
20
|
-
timeoutMs: 30_000
|
|
21
|
-
});
|
|
27
|
+
}
|
|
28
|
+
// 2. web.read(上游 WebChannel.read → Jina Reader)
|
|
29
|
+
{
|
|
30
|
+
const r = await reach({ channel: 'web', method: 'read', args: ['https://example.com'], timeoutMs: 30_000 });
|
|
22
31
|
assert.equal(r.verdict, 'found');
|
|
23
32
|
assert.ok(r.evidence.includes('[agent-reach:web.read@'), '证据链 [agent-reach:web.read@ts]');
|
|
33
|
+
// live 内容会漂移(同 §13),断言非空 markdown 而非精确文案
|
|
24
34
|
assert.ok(typeof r.data === 'string' && r.data.length > 200, 'content 非空 markdown');
|
|
25
35
|
console.log(`2. web.read example.com → found (${r.latencyMs}ms) OK`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
timeoutMs: 30_000
|
|
31
|
-
});
|
|
36
|
+
}
|
|
37
|
+
// 3. v2ex.get_hot_topics(上游 python 方法;网络边界允许降级不抛错)
|
|
38
|
+
{
|
|
39
|
+
const r = await reach({ channel: 'v2ex', method: 'get_hot_topics', timeoutMs: 30_000 });
|
|
32
40
|
if (r.ok) {
|
|
33
41
|
assert.ok(Array.isArray(r.data), 'hot topics 是数组');
|
|
34
42
|
console.log(`3. v2ex.get_hot_topics → found (${r.data.length} topics) OK`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
'needs-setup'
|
|
39
|
-
].includes(r.verdict), '降级合法');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
assert.ok(['error', 'needs-setup'].includes(r.verdict), '降级合法');
|
|
40
46
|
console.log(`3. v2ex.get_hot_topics → ${r.verdict}(网络边界,降级合法) OK`);
|
|
41
47
|
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
args: [
|
|
47
|
-
'SH600519'
|
|
48
|
-
],
|
|
49
|
-
timeoutMs: 30_000
|
|
50
|
-
});
|
|
48
|
+
}
|
|
49
|
+
// 4. xueqiu.get_stock_quote(无 cookie → needs-setup 且 setup 是上游 check() 原话)
|
|
50
|
+
{
|
|
51
|
+
const r = await reach({ channel: 'xueqiu', method: 'get_stock_quote', args: ['SH600519'], timeoutMs: 30_000 });
|
|
51
52
|
assert.equal(r.verdict, 'needs-setup', `实际 verdict=${r.verdict} error=${r.error}`);
|
|
52
53
|
assert.ok((r.setup ?? '').includes('configure'), 'setup 透传上游 configure 指引(不转述)');
|
|
53
54
|
console.log('4. xueqiu.get_stock_quote → needs-setup(上游原话指引) OK');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
});
|
|
55
|
+
}
|
|
56
|
+
// 5. 未知渠道 → 自描述,带回上游渠道清单
|
|
57
|
+
{
|
|
58
|
+
const r = await reach({ channel: 'nosuch', method: 'foo' });
|
|
59
59
|
assert.equal(r.ok, false);
|
|
60
|
-
const channels = r.inventory?.channels ?? {};
|
|
60
|
+
const channels = (r.inventory?.channels ?? {});
|
|
61
61
|
assert.ok(channels.web && channels.xueqiu && channels['exa_search'], 'inventory 带回上游注册表(含 exa_search 真名)');
|
|
62
62
|
console.log(`5. 未知渠道 → 自描述清单(${Object.keys(channels).length} 渠道) OK`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
});
|
|
63
|
+
}
|
|
64
|
+
// 6. 未知方法 → 自描述,带回上游方法签名清单
|
|
65
|
+
{
|
|
66
|
+
const r = await reach({ channel: 'web', method: 'nosuch' });
|
|
68
67
|
assert.equal(r.ok, false);
|
|
69
|
-
const methods = r.inventory?.methods ?? {};
|
|
68
|
+
const methods = (r.inventory?.methods ?? {});
|
|
70
69
|
assert.ok(methods.read, 'inventory.methods 带 read 签名');
|
|
71
70
|
console.log(`6. 未知方法 → 自描述清单(${Object.keys(methods).length} 方法) OK`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
71
|
+
}
|
|
72
|
+
// 7. 永不抛错: 空 channel/method
|
|
73
|
+
{
|
|
74
|
+
const r = await reach({ channel: '', method: '' });
|
|
77
75
|
assert.equal(r.ok, false);
|
|
78
76
|
assert.equal(r.verdict, 'error');
|
|
79
77
|
console.log('7. 空 channel/method 降级 OK');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//# sourceURL=ts/scripts/agent-reach-wrapper-tests.ts
|
|
78
|
+
}
|
|
79
|
+
console.log('\nAGENT-REACH WRAPPER TESTS: 7/7 OK(反射桥 + doctor 透传 + 自描述错误)');
|