@maintainabilityai/research-runner 0.1.15 → 0.1.16

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.
@@ -71,7 +71,10 @@ async function usptoSearch(opts) {
71
71
  patentNumber: num,
72
72
  title: meta.inventionTitle ?? '',
73
73
  abstract: '',
74
- url: num ? `https://patents.google.com/patent/US${num}` : '',
74
+ // earliestPublicationNumber already carries the `US` prefix (e.g.
75
+ // `US20260064729A1`); patentNumber is plain digits. Avoid the double
76
+ // `USUS…` URL we were producing.
77
+ url: num ? `https://patents.google.com/patent/${num.startsWith('US') ? num : `US${num}`}` : '',
75
78
  grantedAt: meta.grantDate || meta.filingDate || meta.effectiveFilingDate || '',
76
79
  inventors: meta.firstInventorName ? [meta.firstInventorName] : [],
77
80
  _xmlUri: xmlUri,
@@ -80,16 +83,33 @@ async function usptoSearch(opts) {
80
83
  // Stage 2: parallel best-effort abstract fetch. The full-text XML carries
81
84
  // the <abstract> element; we regex it out rather than parsing the whole
82
85
  // document (the XML is large and we only want the abstract).
86
+ //
87
+ // Telemetry: count how many we attempted and how many succeeded so the
88
+ // archeologist progress log can surface "uspto abstracts: 3/5" instead of
89
+ // silently shipping empty `>` blockquotes to the synth agent.
90
+ let attempted = 0;
91
+ let succeeded = 0;
92
+ let missingUri = 0;
93
+ const failureCauses = [];
83
94
  await Promise.all(stage1.map(async (r) => {
84
95
  if (!r._xmlUri) {
96
+ missingUri += 1;
85
97
  return;
86
98
  }
99
+ attempted += 1;
87
100
  try {
88
101
  const xmlRes = await fetchImpl(r._xmlUri, {
89
102
  method: 'GET',
90
- headers: { 'X-API-Key': opts.apiKey, accept: 'application/xml' },
103
+ // The signed XML URI lives on a CDN/storage host, not api.uspto.gov.
104
+ // It accepts unauthenticated GETs; sending X-API-Key actually causes
105
+ // some hosts to 403. Use a vanilla request with a polite User-Agent.
106
+ headers: {
107
+ accept: 'application/xml,text/xml,*/*',
108
+ 'user-agent': 'maintainabilityai-research-runner/1.0',
109
+ },
91
110
  });
92
111
  if (!xmlRes.ok) {
112
+ failureCauses.push(`http${xmlRes.status}`);
93
113
  return;
94
114
  }
95
115
  const xml = await xmlRes.text();
@@ -97,10 +117,20 @@ async function usptoSearch(opts) {
97
117
  if (m) {
98
118
  const stripped = m[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
99
119
  r.abstract = stripped.slice(0, 1000);
120
+ succeeded += 1;
100
121
  }
122
+ else {
123
+ failureCauses.push('no-abstract-tag');
124
+ }
125
+ }
126
+ catch (err) {
127
+ failureCauses.push(err instanceof Error ? err.name : 'unknown');
101
128
  }
102
- catch { /* ignore — best-effort */ }
103
129
  }));
130
+ if (records.length > 0 && process.env.RESEARCH_RUNNER_QUIET !== '1') {
131
+ process.stderr.write(`[research-runner] uspto abstracts: ${succeeded}/${attempted} fetched ` +
132
+ `(${missingUri} record(s) had no XML URI; failures: ${failureCauses.join(',') || 'none'})\n`);
133
+ }
104
134
  // Drop the internal _xmlUri marker before returning.
105
135
  const results = stage1.map(({ _xmlUri: _ignored, ...rest }) => rest);
106
136
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maintainabilityai/research-runner",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Research + PRD agent runner — orchestrates the Archeologist and PRD pipelines for the MaintainabilityAI governance mesh",
5
5
  "license": "MIT",
6
6
  "author": "MaintainabilityAI",