@danceiny/gotry 0.0.1-rc.16 → 0.0.1-rc.18

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.
Files changed (229) hide show
  1. package/README.md +161 -116
  2. package/README.zh-CN.md +173 -144
  3. package/bin/gotry-booking-copilot.js +53 -0
  4. package/bin/gotry-bootstrap.js +113 -66
  5. package/bin/gotry-inner.js +436 -70
  6. package/bin/gotry-runtime-resolution.d.ts +27 -0
  7. package/bin/gotry-runtime-resolution.js +50 -0
  8. package/bin/gotry.js +1 -1
  9. package/cordis.gotry-patch.yml +5 -1
  10. package/dist/capabilities/agent-reach-deep.js +1 -1
  11. package/dist/capabilities/agent-reach.js +1 -1
  12. package/dist/capabilities/anything.js +1 -1
  13. package/dist/capabilities/artifacts.js +1 -1
  14. package/dist/capabilities/effect.js +1 -1
  15. package/dist/capabilities/fact-log.js +1 -1
  16. package/dist/capabilities/flyai.js +20 -6
  17. package/dist/capabilities/hbcli.js +1 -1
  18. package/dist/capabilities/incident-log.js +1 -1
  19. package/dist/capabilities/model-override.js +18 -0
  20. package/dist/capabilities/opensky.js +1 -1
  21. package/dist/capabilities/resilience.js +1 -1
  22. package/dist/capabilities/session/action-cache.js +1 -1
  23. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  24. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  25. package/dist/capabilities/session/benchmark.js +1 -1
  26. package/dist/capabilities/session/extension-bridge.js +19 -6
  27. package/dist/capabilities/session/extension-channel.js +3 -3
  28. package/dist/capabilities/session/extension-distribution.js +234 -0
  29. package/dist/capabilities/session/extract.js +1 -1
  30. package/dist/capabilities/session/golden-score.js +92 -0
  31. package/dist/capabilities/session/health-watch.js +1 -1
  32. package/dist/capabilities/session/read-guard.js +1 -1
  33. package/dist/capabilities/session/static-flight-golden.js +137 -0
  34. package/dist/capabilities/session/transport.js +1 -1
  35. package/dist/capabilities/session/wizard.js +21 -251
  36. package/dist/capabilities/session-consent.js +1 -1
  37. package/dist/capabilities/session-login.js +11 -5
  38. package/dist/capabilities/session-search.js +46 -4
  39. package/dist/capabilities/weather.js +168 -46
  40. package/dist/data/session-golden-20.json +25 -0
  41. package/dist/data/sf-golden-manifest.json +102 -0
  42. package/dist/data/sf-static-routes.json +91 -0
  43. package/dist/scripts/action-cache-tests.js +1 -1
  44. package/dist/scripts/agent-planning-budget-e2e.js +227 -0
  45. package/dist/scripts/agent-planning-budget-tests.js +173 -0
  46. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  47. package/dist/scripts/agent-reach-tests.js +1 -1
  48. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  49. package/dist/scripts/anything-tests.js +1 -1
  50. package/dist/scripts/async-collect.js +1 -1
  51. package/dist/scripts/benchmark-environment-bridge-e2e.js +981 -0
  52. package/dist/scripts/benchmark-environment-bridge-tests.js +2544 -0
  53. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +335 -0
  54. package/dist/scripts/booking-copilot-availability-policy-v2-tests.js +1355 -0
  55. package/dist/scripts/booking-copilot-bin-proof-tests.js +89 -0
  56. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +113 -0
  57. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +356 -0
  58. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +557 -0
  59. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +140 -0
  60. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +202 -0
  61. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +102 -0
  62. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +374 -0
  63. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +447 -0
  64. package/dist/scripts/booking-copilot-runtime-proof-tests.js +205 -0
  65. package/dist/scripts/booking-copilot-server-proof-tests.js +317 -0
  66. package/dist/scripts/booking-copilot-startup-proof-tests.js +283 -0
  67. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +3935 -0
  68. package/dist/scripts/booking-saga-tests.js +1 -1
  69. package/dist/scripts/booking-surface-contract-proof-tests.js +393 -0
  70. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +1174 -0
  71. package/dist/scripts/bootstrap-tests.js +45 -39
  72. package/dist/scripts/build-changelog.js +1 -1
  73. package/dist/scripts/changelog-tests.js +1 -1
  74. package/dist/scripts/companion-tests.js +1 -1
  75. package/dist/scripts/diff-test.js +1 -1
  76. package/dist/scripts/dsh-runtime-closure-tests.js +225 -0
  77. package/dist/scripts/dsh-runtime-closure.js +150 -0
  78. package/dist/scripts/effect-tests.js +1 -1
  79. package/dist/scripts/engine-run.js +1 -1
  80. package/dist/scripts/engine-tests.js +1 -1
  81. package/dist/scripts/evaluation-cadence-tests.js +347 -0
  82. package/dist/scripts/evaluation-contract-tests.js +574 -0
  83. package/dist/scripts/extension-distribution-cli.js +35 -0
  84. package/dist/scripts/extension-distribution-tests.js +341 -0
  85. package/dist/scripts/extension-tests.js +128 -23
  86. package/dist/scripts/fact-gate-tests.js +1 -1
  87. package/dist/scripts/flyai-tests.js +1 -1
  88. package/dist/scripts/hbcli-e2e-tests.js +1 -1
  89. package/dist/scripts/hbcli-tests.js +1 -1
  90. package/dist/scripts/health-watch-cli.js +1 -1
  91. package/dist/scripts/i18n-tests.js +1 -1
  92. package/dist/scripts/incident-tests.js +1 -1
  93. package/dist/scripts/journey-tests.js +1 -1
  94. package/dist/scripts/ledger-tests.js +1 -1
  95. package/dist/scripts/ledger-workflow-crash.js +1 -1
  96. package/dist/scripts/memory-capture-tests.js +1 -1
  97. package/dist/scripts/memory-decay-tests.js +1 -1
  98. package/dist/scripts/memory-metrics.js +1 -1
  99. package/dist/scripts/memory-value-report.js +1 -1
  100. package/dist/scripts/model-override-e2e.js +176 -0
  101. package/dist/scripts/nightly-evidence-tests.js +1 -1
  102. package/dist/scripts/nightly-evidence.js +1 -1
  103. package/dist/scripts/nudge-digest.js +1 -1
  104. package/dist/scripts/onboarding-tests.js +21 -53
  105. package/dist/scripts/opensky-check.js +1 -1
  106. package/dist/scripts/opensky-tests.js +1 -1
  107. package/dist/scripts/pnpm-dsh-closure-proof.js +20 -0
  108. package/dist/scripts/price-drift-tests.js +1 -1
  109. package/dist/scripts/price-drift-watch.js +1 -1
  110. package/dist/scripts/probe-poi-tests.js +1 -1
  111. package/dist/scripts/product-metrics.js +1 -1
  112. package/dist/scripts/publish-preverify.js +40 -4
  113. package/dist/scripts/realtime-pricing-tests.js +1 -1
  114. package/dist/scripts/replay-async.js +1 -1
  115. package/dist/scripts/replay-real.js +1 -1
  116. package/dist/scripts/replay.js +1 -1
  117. package/dist/scripts/session-attach-diagnose.js +1 -1
  118. package/dist/scripts/session-attach-poc.js +1 -1
  119. package/dist/scripts/session-benchmark.js +1 -1
  120. package/dist/scripts/session-extract-tests.js +1 -1
  121. package/dist/scripts/session-login.js +1 -1
  122. package/dist/scripts/session-tests.js +70 -20
  123. package/dist/scripts/sf-live-benchmark.js +338 -0
  124. package/dist/scripts/sf-live-cli-tests.js +21 -0
  125. package/dist/scripts/sf-soft-score-tests.js +108 -0
  126. package/dist/scripts/sf-summary.js +93 -0
  127. package/dist/scripts/skeleton-check.js +1 -1
  128. package/dist/scripts/skeleton-integration-test.js +1 -1
  129. package/dist/scripts/skills-contract-tests.js +1 -1
  130. package/dist/scripts/smoke-session-gate-tests.js +29 -0
  131. package/dist/scripts/smoke.js +79 -33
  132. package/dist/scripts/state-cli-tests.js +1 -1
  133. package/dist/scripts/state-cli.js +1 -1
  134. package/dist/scripts/static-golden-tests.js +299 -0
  135. package/dist/scripts/time-eval-tests.js +1 -1
  136. package/dist/scripts/travel-timeline-tests.js +1 -1
  137. package/dist/scripts/unified-tests.js +1 -1
  138. package/dist/scripts/weather-tests.js +694 -44
  139. package/dist/scripts/z3-race-tests.js +1 -1
  140. package/dist/src/artifact-gate.js +1 -1
  141. package/dist/src/benchmark-agent-conformance.js +370 -0
  142. package/dist/src/benchmark-environment-bridge.js +384 -0
  143. package/dist/src/benchmark-headless-child-diagnostics.js +173 -0
  144. package/dist/src/benchmark-tool-isolation.js +124 -0
  145. package/dist/src/bookable-facts.js +1 -1
  146. package/dist/src/booking-saga.js +1 -1
  147. package/dist/src/booking-surface/availability-policy-v2.js +830 -0
  148. package/dist/src/booking-surface/canonical-schema.js +113 -0
  149. package/dist/src/booking-surface/contracts-v2.js +89 -0
  150. package/dist/src/booking-surface/contracts.js +46 -0
  151. package/dist/src/booking-surface/dsh-planner.js +453 -0
  152. package/dist/src/booking-surface/dsh-plugin.js +93 -0
  153. package/dist/src/booking-surface/error-codes.js +94 -0
  154. package/dist/src/booking-surface/index.js +15 -0
  155. package/dist/src/booking-surface/profile.js +68 -0
  156. package/dist/src/booking-surface/runtime-v2.js +1771 -0
  157. package/dist/src/booking-surface/runtime.js +351 -0
  158. package/dist/src/booking-surface/server-v2.js +334 -0
  159. package/dist/src/booking-surface/server.js +302 -0
  160. package/dist/src/booking-surface/startup.js +159 -0
  161. package/dist/src/booking-surface/validation-v2.js +319 -0
  162. package/dist/src/booking-surface/validation.js +809 -0
  163. package/dist/src/bridge.js +1 -1
  164. package/dist/src/companions.js +1 -1
  165. package/dist/src/contracts.js +1 -1
  166. package/dist/src/dsh-llm.js +1 -1
  167. package/dist/src/engine.js +1 -1
  168. package/dist/src/evaluation-cadence.js +234 -0
  169. package/dist/src/evaluation-contracts.js +906 -0
  170. package/dist/src/i18n.js +1 -1
  171. package/dist/src/index.js +50 -19
  172. package/dist/src/journey.js +1 -1
  173. package/dist/src/loop.js +1 -1
  174. package/dist/src/memory-capture.js +1 -1
  175. package/dist/src/memory-decay.js +1 -1
  176. package/dist/src/memory-utility.js +1 -1
  177. package/dist/src/mock-llm.js +1 -1
  178. package/dist/src/model.js +1 -1
  179. package/dist/src/realtime-pricing.js +1 -1
  180. package/dist/src/slot-spec.js +1 -1
  181. package/dist/src/state-ledger.js +2 -1
  182. package/dist/src/time-anchor.js +1 -1
  183. package/dist/src/tool-budget.js +136 -0
  184. package/dist/src/tool-packet.js +1 -1
  185. package/dist/src/travel-slots.js +1 -1
  186. package/dist/src/travel-timeline.js +1 -1
  187. package/dist/src/unified.js +1 -1
  188. package/dist/src/wish-pool.js +1 -1
  189. package/dist/src/z3-shared.js +1 -1
  190. package/extension/README.md +31 -7
  191. package/package.json +286 -11
  192. package/schemas/booking.surface.v1.schema.json +927 -0
  193. package/schemas/booking.surface.v2.schema.json +61 -0
  194. package/ts/capabilities/flyai.ts +16 -3
  195. package/ts/capabilities/session/extension-bridge.ts +37 -14
  196. package/ts/capabilities/session/extension-channel.ts +6 -3
  197. package/ts/capabilities/session/extension-distribution.ts +264 -0
  198. package/ts/capabilities/session/golden-score.ts +139 -0
  199. package/ts/capabilities/session/health-watch.ts +1 -1
  200. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  201. package/ts/capabilities/session/wizard.ts +34 -176
  202. package/ts/capabilities/session-login.ts +15 -5
  203. package/ts/capabilities/session-search.ts +40 -3
  204. package/ts/capabilities/weather.ts +141 -52
  205. package/ts/package.json +3 -3
  206. package/ts/src/benchmark-agent-conformance.ts +448 -0
  207. package/ts/src/benchmark-environment-bridge.ts +348 -0
  208. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  209. package/ts/src/benchmark-tool-isolation.ts +166 -0
  210. package/ts/src/booking-surface/availability-policy-v2.ts +523 -0
  211. package/ts/src/booking-surface/canonical-schema.js +113 -0
  212. package/ts/src/booking-surface/contracts-v2.ts +118 -0
  213. package/ts/src/booking-surface/contracts.ts +380 -0
  214. package/ts/src/booking-surface/dsh-planner.ts +452 -0
  215. package/ts/src/booking-surface/dsh-plugin.js +93 -0
  216. package/ts/src/booking-surface/error-codes.ts +101 -0
  217. package/ts/src/booking-surface/index.ts +12 -0
  218. package/ts/src/booking-surface/profile.ts +42 -0
  219. package/ts/src/booking-surface/runtime-v2.ts +1466 -0
  220. package/ts/src/booking-surface/runtime.ts +483 -0
  221. package/ts/src/booking-surface/server-v2.ts +247 -0
  222. package/ts/src/booking-surface/server.ts +324 -0
  223. package/ts/src/booking-surface/startup.ts +196 -0
  224. package/ts/src/booking-surface/validation-v2.ts +205 -0
  225. package/ts/src/booking-surface/validation.ts +453 -0
  226. package/ts/src/index.ts +64 -11
  227. package/ts/src/state-ledger.ts +1 -0
  228. package/ts/src/tool-budget.ts +165 -0
  229. package/dist/scripts/wizard-bootstrap.js +0 -32
@@ -0,0 +1,227 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createServer } from 'node:http';
3
+ import { existsSync, mkdtempSync, rmSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { spawn } from 'node:child_process';
7
+ const ROOT = join(import.meta.dirname, '..', '..');
8
+ const TIMEOUT_MS = 90_000;
9
+ const TOOL = 'gotry_artifacts_list';
10
+ const EXHAUSTED = 'TOOL_BUDGET_EXHAUSTED';
11
+ function sse(data) {
12
+ return `data: ${JSON.stringify(data)}\n\n`;
13
+ }
14
+ function toolResponse(number) {
15
+ const count = number === 18 ? 2 : 1;
16
+ const calls = Array.from({
17
+ length: count
18
+ }, (_, index)=>({
19
+ index,
20
+ id: `budget-call-${number}-${index + 1}`,
21
+ type: 'function',
22
+ function: {
23
+ name: TOOL,
24
+ arguments: JSON.stringify({
25
+ query: {
26
+ limit: 1
27
+ }
28
+ })
29
+ }
30
+ }));
31
+ return sse({
32
+ id: `budget-${number}`,
33
+ object: 'chat.completion.chunk',
34
+ created: 1,
35
+ model: 'synthetic-budget-model',
36
+ choices: [
37
+ {
38
+ index: 0,
39
+ delta: {
40
+ role: 'assistant',
41
+ tool_calls: calls
42
+ },
43
+ finish_reason: null
44
+ }
45
+ ]
46
+ }) + sse({
47
+ id: `budget-${number}-finish`,
48
+ object: 'chat.completion.chunk',
49
+ created: 1,
50
+ model: 'synthetic-budget-model',
51
+ choices: [
52
+ {
53
+ index: 0,
54
+ delta: {},
55
+ finish_reason: 'tool_calls'
56
+ }
57
+ ]
58
+ }) + 'data: [DONE]\n\n';
59
+ }
60
+ function textResponse(text, id = 'budget-final') {
61
+ return sse({
62
+ id,
63
+ object: 'chat.completion.chunk',
64
+ created: 1,
65
+ model: 'synthetic-budget-model',
66
+ choices: [
67
+ {
68
+ index: 0,
69
+ delta: {
70
+ role: 'assistant',
71
+ content: text
72
+ },
73
+ finish_reason: null
74
+ }
75
+ ]
76
+ }) + sse({
77
+ id: `${id}-finish`,
78
+ object: 'chat.completion.chunk',
79
+ created: 1,
80
+ model: 'synthetic-budget-model',
81
+ choices: [
82
+ {
83
+ index: 0,
84
+ delta: {},
85
+ finish_reason: 'stop'
86
+ }
87
+ ]
88
+ }) + 'data: [DONE]\n\n';
89
+ }
90
+ async function startRelay() {
91
+ const bodies = [];
92
+ const plannerBodies = [];
93
+ const server = createServer((req, res)=>{
94
+ if (req.method !== 'POST' || !req.url?.endsWith('/chat/completions')) {
95
+ res.writeHead(404).end('not found');
96
+ return;
97
+ }
98
+ const chunks = [];
99
+ req.on('data', (chunk)=>chunks.push(Buffer.from(chunk)));
100
+ req.on('end', ()=>{
101
+ let body;
102
+ try {
103
+ body = JSON.parse(Buffer.concat(chunks).toString('utf8'));
104
+ } catch {
105
+ body = {};
106
+ }
107
+ bodies.push(body);
108
+ res.writeHead(200, {
109
+ 'content-type': 'text/event-stream',
110
+ 'cache-control': 'no-cache'
111
+ });
112
+ if (toolNames(body).includes(TOOL)) {
113
+ plannerBodies.push(body);
114
+ res.end(toolResponse(plannerBodies.length));
115
+ } else if (plannerBodies.length >= 18) {
116
+ res.end(textResponse('budget E2E final answer'));
117
+ } else {
118
+ res.end(textResponse('budget e2e title', 'budget-auxiliary'));
119
+ }
120
+ });
121
+ });
122
+ await new Promise((resolve)=>server.listen(0, '127.0.0.1', resolve));
123
+ return {
124
+ port: server.address().port,
125
+ bodies,
126
+ plannerBodies,
127
+ close: ()=>new Promise((resolve)=>server.close(()=>resolve()))
128
+ };
129
+ }
130
+ function allToolMessages(bodies) {
131
+ return bodies.flatMap((body)=>(body.messages ?? []).filter((message)=>message.role === 'tool'));
132
+ }
133
+ function toolNames(body) {
134
+ return (body.tools ?? []).map((tool)=>{
135
+ const fn = tool.function;
136
+ return String(fn?.name ?? tool.name ?? '');
137
+ }).filter(Boolean);
138
+ }
139
+ async function main() {
140
+ for (const file of [
141
+ 'dist/src/index.js',
142
+ 'dist/capabilities/artifacts.js'
143
+ ]){
144
+ assert.ok(existsSync(join(ROOT, file)), `missing ${file}; run node scripts/build-dist.mjs first`);
145
+ }
146
+ const relay = await startRelay();
147
+ const dshHome = mkdtempSync(join(tmpdir(), 'gotry-budget-dsh-home-'));
148
+ const childCwd = mkdtempSync(join(tmpdir(), 'gotry-budget-cwd-'));
149
+ let exitCode = null;
150
+ let output = '';
151
+ const configuredBin = process.env.GOTRY_BUDGET_E2E_BIN;
152
+ assert.ok(configuredBin && existsSync(configuredBin), 'GOTRY_BUDGET_E2E_BIN must point to the clean installed-package binary');
153
+ try {
154
+ const executable = configuredBin;
155
+ const executableArgs = [
156
+ 'exercise the tool budget'
157
+ ];
158
+ const childEnv = {
159
+ ...process.env
160
+ };
161
+ childEnv.DSH_HOME = dshHome;
162
+ childEnv.LLM_API_KEY = 'synthetic-e2e-key';
163
+ childEnv.LLM_BASE_URL = 'http://127.0.0.1:' + relay.port + '/v1';
164
+ childEnv.LLM_MODEL = 'synthetic-budget-model';
165
+ childEnv.GOTRY_LOCALE = 'zh-CN';
166
+ childEnv.GOTRY_DISABLE_OPTIONAL_CALENDAR = '1';
167
+ delete childEnv.GOTRY_LLM_MODEL;
168
+ const child = spawn(executable, executableArgs, {
169
+ cwd: childCwd,
170
+ env: childEnv,
171
+ stdio: [
172
+ 'ignore',
173
+ 'pipe',
174
+ 'pipe'
175
+ ]
176
+ });
177
+ child.stdout.on('data', (chunk)=>{
178
+ output += chunk.toString();
179
+ });
180
+ child.stderr.on('data', (chunk)=>{
181
+ output += chunk.toString();
182
+ });
183
+ exitCode = await new Promise((resolve)=>{
184
+ const timer = setTimeout(()=>{
185
+ child.kill('SIGKILL');
186
+ resolve(null);
187
+ }, TIMEOUT_MS);
188
+ child.once('exit', (code)=>{
189
+ clearTimeout(timer);
190
+ resolve(code);
191
+ });
192
+ });
193
+ } finally{
194
+ await relay.close();
195
+ rmSync(dshHome, {
196
+ recursive: true,
197
+ force: true
198
+ });
199
+ rmSync(childCwd, {
200
+ recursive: true,
201
+ force: true
202
+ });
203
+ }
204
+ assert.equal(exitCode, 0, `headless exit=${exitCode}; output tail=${output.slice(-1200)}`);
205
+ assert.equal(relay.plannerBodies.length, 18, `expected 18 tool-enabled planner requests, got ${relay.plannerBodies.length}; output tail=${output.slice(-12_000)}`);
206
+ const finalRequest = relay.bodies.at(-1);
207
+ const toolMessages = allToolMessages([
208
+ finalRequest
209
+ ]);
210
+ const normalResults = toolMessages.filter((message)=>!JSON.stringify(message).includes(EXHAUSTED));
211
+ const exhaustedResults = toolMessages.filter((message)=>JSON.stringify(message).includes(EXHAUSTED));
212
+ const toolMessageDiagnostic = JSON.stringify(toolMessages).slice(-12_000);
213
+ assert.equal(normalResults.length, 18, `exactly 18 real tool results/body dispatches; messages=${toolMessageDiagnostic}`);
214
+ assert.ok(normalResults.every((message)=>JSON.stringify(message).includes('无在册产物')), `all 18 bodies must return the registered artifact-list result; messages=${toolMessageDiagnostic}`);
215
+ assert.equal(exhaustedResults.length, 1, `19th call returns one structured exhaustion result; messages=${toolMessageDiagnostic}`);
216
+ assert.ok(JSON.stringify(exhaustedResults[0]).includes(EXHAUSTED));
217
+ assert.equal(exhaustedResults[0]?.tool_call_id, 'budget-call-18-2');
218
+ const finalNames = toolNames(finalRequest);
219
+ assert.ok(!finalNames.includes(TOOL), `final request inherited GoTry tool: ${finalNames.join(', ')}`);
220
+ assert.equal(finalNames.length, 0, `final request must be text-only, got ${finalNames.join(', ')}`);
221
+ assert.match(output, /budget E2E final answer/);
222
+ console.log(`agent planning budget E2E: OK (exit=${exitCode}, plannerRequests=${relay.plannerBodies.length}, allModelRequests=${relay.bodies.length}, realToolResults=${normalResults.length}, exhausted=${exhaustedResults.length})`);
223
+ }
224
+ await main();
225
+
226
+
227
+ //# sourceURL=ts/scripts/agent-planning-budget-e2e.ts
@@ -0,0 +1,173 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createToolBudgetState, installToolBudget, TOOL_BUDGET_EXHAUSTED, toolBudgetDecision } from '../src/tool-budget.js';
3
+ const success = ()=>({
4
+ isError: false,
5
+ value: null,
6
+ content: []
7
+ });
8
+ const handlers = new Map();
9
+ const restricted = [];
10
+ const lifted = [];
11
+ const makeAgent = (id)=>({
12
+ id,
13
+ ctx: {
14
+ tools: {
15
+ restrict (filter) {
16
+ restricted.push({
17
+ agentId: id,
18
+ deny: [
19
+ ...filter.deny
20
+ ]
21
+ });
22
+ return ()=>lifted.push(id);
23
+ }
24
+ }
25
+ }
26
+ });
27
+ const ctx = {
28
+ tools: {
29
+ schemas: ()=>[
30
+ {
31
+ name: 'gotry_alpha'
32
+ },
33
+ {
34
+ name: 'gotry_beta'
35
+ }
36
+ ]
37
+ },
38
+ on (event, listener) {
39
+ const bucket = handlers.get(event) ?? [];
40
+ bucket.push(listener);
41
+ handlers.set(event, bucket);
42
+ return ()=>{};
43
+ }
44
+ };
45
+ installToolBudget(ctx);
46
+ const execute = handlers.get('tools/execute')?.[0];
47
+ const postExecute = handlers.get('tools/post-execute')?.[0];
48
+ const sessionEvent = handlers.get('session/event')?.[0];
49
+ const sessionDisposed = handlers.get('session/disposed')?.[0];
50
+ assert.ok(execute && postExecute && sessionEvent && sessionDisposed, 'all Cordis budget hooks register');
51
+ assert.deepEqual(toolBudgetDecision(18), {
52
+ kind: 'allow',
53
+ softSignal: false,
54
+ exhaustsBudget: true
55
+ });
56
+ const pureExhausted = toolBudgetDecision(19);
57
+ assert.equal(pureExhausted.kind, 'deny');
58
+ if (pureExhausted.kind === 'deny') assert.match(pureExhausted.reason, /TOOL_BUDGET_EXHAUSTED/);
59
+ const freshState = createToolBudgetState();
60
+ assert.equal(freshState.nextCall().callNumber, 1);
61
+ let directBodies = 0;
62
+ for(let i = 0; i < 25; i++){
63
+ const result = await execute({
64
+ token: Symbol(`direct-${i}`)
65
+ }, async ()=>{
66
+ directBodies++;
67
+ return success();
68
+ });
69
+ assert.equal(result.isError, false);
70
+ }
71
+ assert.equal(directBodies, 25);
72
+ const agent = makeAgent('agent-serial');
73
+ let serialBodies = 0;
74
+ let softSignals = 0;
75
+ for(let attempt = 1; attempt <= 18; attempt++){
76
+ const exec = {
77
+ token: Symbol(`serial-${attempt}`),
78
+ agent
79
+ };
80
+ const result = await execute(exec, async ()=>{
81
+ serialBodies++;
82
+ return success();
83
+ });
84
+ const post = await postExecute(exec, result, async ()=>({
85
+ kind: 'accept'
86
+ }));
87
+ const contextText = post.additionalContexts?.flatMap((item)=>item.content ?? []).map((item)=>item.text ?? '').join('\n') ?? '';
88
+ if (contextText.includes('TOOL_BUDGET_SOFT')) softSignals++;
89
+ }
90
+ assert.equal(serialBodies, 18);
91
+ assert.equal(softSignals, 1);
92
+ assert.equal(restricted.length, 0, 'same-step prepared calls remain resolvable until step/end');
93
+ let nineteenthBodyRan = false;
94
+ const nineteenth = await execute({
95
+ token: Symbol('serial-19'),
96
+ agent
97
+ }, async ()=>{
98
+ nineteenthBodyRan = true;
99
+ return success();
100
+ });
101
+ assert.equal(nineteenthBodyRan, false);
102
+ assert.equal(nineteenth.isError, true);
103
+ assert.deepEqual(nineteenth.error?.info, {
104
+ name: 'ToolBudgetError',
105
+ code: TOOL_BUDGET_EXHAUSTED
106
+ });
107
+ assert.match(nineteenth.content[0]?.text ?? '', /TOOL_BUDGET_EXHAUSTED/);
108
+ assert.match(nineteenth.additionalContexts?.[0]?.content?.[0]?.text ?? '', /Produce the final answer/);
109
+ sessionEvent({
110
+ id: agent.id
111
+ }, {
112
+ type: 'step/end'
113
+ });
114
+ assert.deepEqual(restricted.at(-1), {
115
+ agentId: agent.id,
116
+ deny: [
117
+ 'gotry_alpha',
118
+ 'gotry_beta'
119
+ ]
120
+ });
121
+ sessionEvent({
122
+ id: agent.id
123
+ }, {
124
+ type: 'turn/end'
125
+ });
126
+ assert.equal(lifted.at(-1), agent.id);
127
+ sessionEvent({
128
+ id: agent.id
129
+ }, {
130
+ type: 'turn/start'
131
+ });
132
+ const afterReset = await execute({
133
+ token: Symbol('new-turn-1'),
134
+ agent
135
+ }, async ()=>success());
136
+ assert.equal(afterReset.isError, false);
137
+ const parallelAgent = makeAgent('agent-parallel');
138
+ let parallelBodies = 0;
139
+ const parallelResults = await Promise.all(Array.from({
140
+ length: 19
141
+ }, async (_, index)=>{
142
+ return execute({
143
+ token: Symbol(`parallel-${index + 1}`),
144
+ agent: parallelAgent
145
+ }, async ()=>{
146
+ parallelBodies++;
147
+ await Promise.resolve();
148
+ return success();
149
+ });
150
+ }));
151
+ assert.equal(parallelBodies, 18);
152
+ assert.equal(parallelResults.filter((result)=>result.isError).length, 1);
153
+ assert.equal(parallelResults.find((result)=>result.isError)?.error?.info?.code, TOOL_BUDGET_EXHAUSTED);
154
+ sessionEvent({
155
+ id: parallelAgent.id
156
+ }, {
157
+ type: 'step/end'
158
+ });
159
+ assert.deepEqual(restricted.at(-1), {
160
+ agentId: parallelAgent.id,
161
+ deny: [
162
+ 'gotry_alpha',
163
+ 'gotry_beta'
164
+ ]
165
+ });
166
+ sessionDisposed({
167
+ id: parallelAgent.id
168
+ });
169
+ assert.equal(lifted.at(-1), parallelAgent.id);
170
+ console.log('agent planning tool budget tests: OK (Cordis execute/post/lifecycle/parallel integration)');
171
+
172
+
173
+ //# sourceURL=ts/scripts/agent-planning-budget-tests.ts
@@ -51,4 +51,4 @@ import { videoSubtitle, githubSearch } from '../capabilities/agent-reach-deep.js
51
51
  }console.log('\nAGENT-REACH DEEP TESTS: 4/4 OK(yt-dlp/gh 可选工具,不装则降级)');
52
52
 
53
53
 
54
- //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/agent-reach-deep-tests.ts
54
+ //# sourceURL=ts/scripts/agent-reach-deep-tests.ts
@@ -35,4 +35,4 @@ import { readUrl } from '../capabilities/agent-reach.js';
35
35
  }console.log('\nAGENT-REACH TESTS: 3/3 OK(readUrl 薄壳;上游真读见 wrapper 套)');
36
36
 
37
37
 
38
- //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/agent-reach-tests.ts
38
+ //# sourceURL=ts/scripts/agent-reach-tests.ts
@@ -80,4 +80,4 @@ import { reach, reachStatus } from '../capabilities/agent-reach.js';
80
80
  }console.log('\nAGENT-REACH WRAPPER TESTS: 7/7 OK(反射桥 + doctor 透传 + 自描述错误)');
81
81
 
82
82
 
83
- //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/agent-reach-wrapper-tests.ts
83
+ //# sourceURL=ts/scripts/agent-reach-wrapper-tests.ts
@@ -92,4 +92,4 @@ while :; do sleep 5; done
92
92
  }
93
93
 
94
94
 
95
- //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/anything-tests.ts
95
+ //# sourceURL=ts/scripts/anything-tests.ts
@@ -62,4 +62,4 @@ console.log(JSON.stringify(outcome));
62
62
  process.exitCode = outcome.status === 'succeeded' ? 0 : 2;
63
63
 
64
64
 
65
- //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/async-collect.ts
65
+ //# sourceURL=ts/scripts/async-collect.ts