@danceiny/gotry 0.0.1-rc.7 → 0.0.1-rc.9

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 (75) hide show
  1. package/README.md +29 -74
  2. package/bin/gotry-inner.js +50 -1
  3. package/bin/gotry-stdio-ask.js +59 -0
  4. package/cordis.gotry-patch.yml +63 -5
  5. package/data/flights_2026.json +7 -4
  6. package/data/hotels_2026.json +102 -15
  7. package/data/time-slot-eval.json +384 -0
  8. package/data/yunnan-pack.json +2 -1
  9. package/dist/capabilities/agent-reach-bridge.py +90 -0
  10. package/dist/capabilities/anything.js +2 -2
  11. package/dist/capabilities/flyai.js +131 -0
  12. package/dist/capabilities/hbcli.js +11 -6
  13. package/dist/capabilities/incident-log.js +2 -1
  14. package/dist/capabilities/session/action-cache.js +120 -0
  15. package/dist/capabilities/session/adapters/ctrip-flight.js +83 -0
  16. package/dist/capabilities/session/adapters/meituan-local.js +73 -0
  17. package/dist/capabilities/session/extract.js +40 -0
  18. package/dist/capabilities/session/read-guard.js +56 -0
  19. package/dist/capabilities/session/transport.js +95 -0
  20. package/dist/capabilities/session-search.js +95 -0
  21. package/dist/scripts/action-cache-tests.js +107 -0
  22. package/dist/scripts/agent-reach-tests.js +1 -1
  23. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  24. package/dist/scripts/async-collect.js +26 -7
  25. package/dist/scripts/companion-tests.js +112 -0
  26. package/dist/scripts/hbcli-tests.js +18 -2
  27. package/dist/scripts/ledger-tests.js +344 -0
  28. package/dist/scripts/ledger-workflow-crash.js +42 -0
  29. package/dist/scripts/memory-capture-tests.js +77 -0
  30. package/dist/scripts/memory-decay-tests.js +83 -0
  31. package/dist/scripts/memory-metrics.js +24 -0
  32. package/dist/scripts/nudge-digest.js +83 -0
  33. package/dist/scripts/probe-poi-tests.js +9 -0
  34. package/dist/scripts/replay.js +73 -1
  35. package/dist/scripts/session-attach-diagnose.js +31 -0
  36. package/dist/scripts/session-attach-poc.js +65 -0
  37. package/dist/scripts/session-attach-wait.js +41 -0
  38. package/dist/scripts/session-extract-tests.js +81 -0
  39. package/dist/scripts/session-login.js +48 -0
  40. package/dist/scripts/session-tests.js +162 -0
  41. package/dist/scripts/skeleton-check.js +3 -1
  42. package/dist/scripts/skills-contract-tests.js +85 -0
  43. package/dist/scripts/smoke.js +242 -4
  44. package/dist/scripts/state-cli-tests.js +136 -0
  45. package/dist/scripts/state-cli.js +234 -0
  46. package/dist/scripts/time-eval-tests.js +318 -0
  47. package/dist/scripts/travel-timeline-tests.js +123 -0
  48. package/dist/scripts/unified-tests.js +1 -1
  49. package/dist/src/companions.js +112 -0
  50. package/dist/src/dsh-llm.js +27 -7
  51. package/dist/src/index.js +600 -121
  52. package/dist/src/loop.js +89 -25
  53. package/dist/src/memory-capture.js +40 -0
  54. package/dist/src/memory-decay.js +31 -0
  55. package/dist/src/memory-utility.js +55 -0
  56. package/dist/src/mock-llm.js +6 -1
  57. package/dist/src/slot-spec.js +165 -0
  58. package/dist/src/state-ledger.js +848 -0
  59. package/dist/src/time-anchor.js +100 -0
  60. package/dist/src/tool-packet.js +12 -0
  61. package/dist/src/travel-slots.js +144 -0
  62. package/dist/src/travel-timeline.js +78 -0
  63. package/dist/src/unified.js +3 -1
  64. package/dist/src/wish-pool.js +27 -0
  65. package/package.json +6 -2
  66. package/ts/capabilities/hbcli.ts +6 -6
  67. package/ts/capabilities/incident-log.ts +6 -3
  68. package/ts/package.json +3 -0
  69. package/ts/scripts/skeleton-check.ts +5 -1
  70. package/ts/src/dsh-llm.ts +27 -7
  71. package/ts/src/index.ts +439 -91
  72. package/ts/src/loop.ts +109 -34
  73. package/ts/src/mock-llm.ts +13 -1
  74. package/ts/src/unified.ts +6 -1
  75. package/ts/cordis.gotry-patch.yml +0 -36
@@ -0,0 +1,112 @@
1
+ const SENSITIVE_PATTERNS = [
2
+ {
3
+ re: /\d{15,17}[Xx]?/,
4
+ label: '疑似证件号/卡号'
5
+ },
6
+ {
7
+ re: /1[3-9]\d{9}/,
8
+ label: '疑似手机号'
9
+ },
10
+ {
11
+ re: /(护照|身份证|证件号|通行证)\s*号?\s*[::]?\s*\w+/i,
12
+ label: '证件信息'
13
+ }
14
+ ];
15
+ export function sensitiveViolation(text) {
16
+ for (const { re, label } of SENSITIVE_PATTERNS){
17
+ if (re.test(text)) return `负面清单拒收:${label}不入库(需要时由后端从登录态填充)`;
18
+ }
19
+ return null;
20
+ }
21
+ export function companionId(label) {
22
+ return label.replace(/\s+/g, '');
23
+ }
24
+ function mergeStrArray(oldArr, newArr) {
25
+ const a = oldArr ?? [];
26
+ let added = false;
27
+ for (const x of newArr ?? []){
28
+ if (!a.includes(x)) {
29
+ a.push(x);
30
+ added = true;
31
+ }
32
+ }
33
+ return {
34
+ merged: a,
35
+ added
36
+ };
37
+ }
38
+ export function upsertCompanion(profiles, patch) {
39
+ if (!patch.label?.trim()) return {
40
+ profiles,
41
+ appended: false,
42
+ companionId: '',
43
+ reason: 'label 必填'
44
+ };
45
+ const violation = sensitiveViolation(JSON.stringify(patch));
46
+ if (violation) return {
47
+ profiles,
48
+ appended: false,
49
+ companionId: '',
50
+ reason: violation
51
+ };
52
+ const id = companionId(patch.label);
53
+ const existing = profiles.find((p)=>p.companion_id === id);
54
+ if (!existing) {
55
+ const full = {
56
+ schema: 'companion_profile.v1',
57
+ companion_id: id,
58
+ label: patch.label.trim(),
59
+ constraints: {
60
+ mobility: patch.constraints.mobility,
61
+ health: patch.constraints.health ? [
62
+ ...patch.constraints.health
63
+ ] : undefined,
64
+ prefs: patch.constraints.prefs ? [
65
+ ...patch.constraints.prefs
66
+ ] : undefined
67
+ },
68
+ evidence: [
69
+ patch.evidence
70
+ ],
71
+ ts: new Date().toISOString()
72
+ };
73
+ return {
74
+ profiles: [
75
+ ...profiles,
76
+ full
77
+ ],
78
+ appended: true,
79
+ companionId: id
80
+ };
81
+ }
82
+ const mergedConstraints = {
83
+ mobility: patch.constraints.mobility ?? existing.constraints.mobility,
84
+ health: mergeStrArray(existing.constraints.health, patch.constraints.health).merged,
85
+ prefs: mergeStrArray(existing.constraints.prefs, patch.constraints.prefs).merged
86
+ };
87
+ const ev = mergeStrArray(existing.evidence, [
88
+ patch.evidence
89
+ ]);
90
+ const healthLen = mergedConstraints.health?.length ?? 0;
91
+ const prefsLen = mergedConstraints.prefs?.length ?? 0;
92
+ const changed = mergedConstraints.mobility !== existing.constraints.mobility || healthLen !== (existing.constraints.health?.length ?? 0) || prefsLen !== (existing.constraints.prefs?.length ?? 0) || ev.added;
93
+ if (!changed) return {
94
+ profiles,
95
+ appended: false,
96
+ companionId: id
97
+ };
98
+ const next = profiles.map((p)=>p.companion_id === id ? {
99
+ ...p,
100
+ constraints: mergedConstraints,
101
+ evidence: ev.merged,
102
+ ts: new Date().toISOString()
103
+ } : p);
104
+ return {
105
+ profiles: next,
106
+ appended: true,
107
+ companionId: id
108
+ };
109
+ }
110
+
111
+
112
+ //# sourceURL=/Users/bytedance/work/gotry/ts/src/companions.ts
@@ -1,17 +1,19 @@
1
1
  import { parseFlightPackToSpec } from './unified.js';
2
- const MODEL = process.env['LLM_MODEL'] ?? process.env['DEEPSEEK_MODEL'] ?? 'MiniMax-M2';
3
- const BASE = (process.env['LLM_BASE_URL'] ?? process.env['DEEPSEEK_BASE_URL'] ?? 'https://api.minimax.io/v1').replace(/\/$/, '');
2
+ import { buildTimeAnchor } from './time-anchor.js';
3
+ import { buildSlotSystem, flagExpiredSlots, normalizeExtraction } from './travel-slots.js';
4
+ const model = ()=>process.env['LLM_MODEL'] ?? process.env['DEEPSEEK_MODEL'] ?? 'MiniMax-M2';
5
+ const base = ()=>(process.env['LLM_BASE_URL'] ?? process.env['DEEPSEEK_BASE_URL'] ?? 'https://api.minimax.io/v1').replace(/\/$/, '');
4
6
  async function chat(messages, json) {
5
7
  const key = process.env['LLM_API_KEY'] ?? process.env['DEEPSEEK_API_KEY'];
6
8
  if (!key) throw new Error('LLM_API_KEY 未设置(兼容 DEEPSEEK_API_KEY 别名)——真 LLM 路径不可用,请回退 mock(ADR-8)');
7
- const res = await fetch(`${BASE}/chat/completions`, {
9
+ const res = await fetch(`${base()}/chat/completions`, {
8
10
  method: 'POST',
9
11
  headers: {
10
12
  'Content-Type': 'application/json',
11
13
  Authorization: `Bearer ${key}`
12
14
  },
13
15
  body: JSON.stringify({
14
- model: MODEL,
16
+ model: model(),
15
17
  messages,
16
18
  ...json ? {
17
19
  response_format: {
@@ -46,9 +48,10 @@ const SKELETON_SYSTEM = `你是行程骨架抽取器。从对话中抽取行程
46
48
  输出 JSON:{"scenario":"erhai|workation|yunnan|generic","segments":[{"id":"f1","role":"choice|fixed","route":"HKG->HKT","dateHint":"2026-07-18","anchors":{"arriveByMin":885}}]}
47
49
  规则:每个跨城移动一段;锚点只放用户明说或必然的(如"当天到"→arriveByMin 23:59=1439);时刻用当日分钟。
48
50
  scenario 判定:「洱海/大理/千岛湖/太湖+选目的地」→erhai(候选集);「普吉/workation/远程办公+多城链」→workation(五段链);「云南/大理丽江」→yunnan;不确定→generic。只输出 JSON。`;
49
- export function createOpenAICompatLlm(flightPackPath) {
51
+ export function createOpenAICompatLlm(flightPackPath, clock = ()=>new Date()) {
50
52
  const pack = flightPackPath;
51
53
  const historyText = (h)=>h.map((t)=>`${t.role === 'user' ? '用户' : '助手'}: ${t.text}`).join('\n');
54
+ const anchorContext = ()=>`时间锚点卡:\n${buildTimeAnchor(clock()).card}`;
52
55
  return {
53
56
  async extractFacts (history) {
54
57
  const out = await chat([
@@ -58,7 +61,7 @@ export function createOpenAICompatLlm(flightPackPath) {
58
61
  },
59
62
  {
60
63
  role: 'user',
61
- content: historyText(history)
64
+ content: `${anchorContext()}\n\n${historyText(history)}`
62
65
  }
63
66
  ], true);
64
67
  const obj = parseJsonBlock(out);
@@ -78,7 +81,7 @@ export function createOpenAICompatLlm(flightPackPath) {
78
81
  };
79
82
  },
80
83
  async extractSpec (history, state) {
81
- const context = `已断言日历:${JSON.stringify(state.calendar.assertedWeekdays)}\nprofile:${JSON.stringify(state.profile)}`;
84
+ const context = `${anchorContext()}\n已断言日历:${JSON.stringify(state.calendar.assertedWeekdays)}\nprofile:${JSON.stringify(state.profile)}`;
82
85
  const out = await chat([
83
86
  {
84
87
  role: 'system',
@@ -134,6 +137,23 @@ export function createOpenAICompatLlm(flightPackPath) {
134
137
  packSpec.budgetCny = 9000;
135
138
  return packSpec;
136
139
  },
140
+ async extractSlots (history, now) {
141
+ const anchor = buildTimeAnchor(now ?? clock());
142
+ const out = await chat([
143
+ {
144
+ role: 'system',
145
+ content: buildSlotSystem(anchor)
146
+ },
147
+ {
148
+ role: 'user',
149
+ content: historyText(history)
150
+ }
151
+ ], true);
152
+ const obj = parseJsonBlock(out);
153
+ if (!obj) return null;
154
+ const ext = normalizeExtraction(obj, history.map((t)=>t.text).join('\n'));
155
+ return ext ? flagExpiredSlots(ext, anchor) : null;
156
+ },
137
157
  async polishQuestion (q) {
138
158
  const out = await chat([
139
159
  {