@neuledge/graph 0.1.0
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/LICENSE +202 -0
- package/README.md +381 -0
- package/bin/cli.js +93 -0
- package/dist/api-fetch.d.ts +11 -0
- package/dist/api-fetch.js +31 -0
- package/dist/api-fetch.js.map +1 -0
- package/dist/error.d.ts +9 -0
- package/dist/error.js +22 -0
- package/dist/error.js.map +1 -0
- package/dist/graph.d.ts +13 -0
- package/dist/graph.js +13 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/lookup.d.ts +36 -0
- package/dist/lookup.js +111 -0
- package/dist/lookup.js.map +1 -0
- package/dist/match.d.ts +7 -0
- package/dist/match.js +2 -0
- package/dist/match.js.map +1 -0
- package/package.json +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# @neuledge/graph
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
**Give LLMs real knowledge — structured, live, and reliable — so they reason with facts, not guesses.**
|
|
7
|
+
|
|
8
|
+
[](https://www.npmjs.com/package/@neuledge/graph)
|
|
9
|
+
[](https://github.com/neuledge/graph/blob/main/LICENSE)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
|
|
12
|
+
[How it works](#-how-it-works) • [Examples](#-examples) • [Installation](#-installation) • [API Reference](#-api-reference)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
`@neuledge/graph` connects your AI to live, structured data sources so your models can answer with certainty. Stop hallucinations before they happen by grounding your LLM in real-time, verified data.
|
|
21
|
+
|
|
22
|
+
### Why @neuledge/graph?
|
|
23
|
+
|
|
24
|
+
Your AI agent gets asked: *"What's the weather in Tokyo?"*
|
|
25
|
+
|
|
26
|
+
**Your options:**
|
|
27
|
+
1. 🤷 **Let the LLM guess** → "Tokyo is typically mild this time of year..." (Wrong)
|
|
28
|
+
2. 🐌 **Web search tool** → 3-5 seconds, parse HTML, unstructured results
|
|
29
|
+
3. 🔧 **Build custom integration** → Sign up for API, handle auth, write parsers
|
|
30
|
+
4. ⚡ **Use @neuledge/graph** → `lookup({ query: "cities.tokyo.weather" })` → Done in <100ms
|
|
31
|
+
|
|
32
|
+
**One tool. Live data. Zero setup.**
|
|
33
|
+
|
|
34
|
+
- ✅ **Instant** - Pre-fetched & cached data returns in <100ms
|
|
35
|
+
- ✅ **Structured** - Clean JSON your LLM can reason about
|
|
36
|
+
- ✅ **Trusted** - Real sources, not scraped web pages
|
|
37
|
+
- ✅ **Universal** - Same tool for weather, stocks, FX, and more
|
|
38
|
+
|
|
39
|
+
<br>
|
|
40
|
+
|
|
41
|
+
## ⚡ How it works
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// 1. Create a knowledge graph instance
|
|
45
|
+
const graph = new NeuledgeGraph();
|
|
46
|
+
|
|
47
|
+
// 2. Pass the lookup tool to your AI agent
|
|
48
|
+
const agent = new Agent({
|
|
49
|
+
model: 'claude-sonnet-4-5',
|
|
50
|
+
tools: { lookup: tool(graph.lookup) },
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// 3. Ask questions - the agent will fetch live data automatically
|
|
54
|
+
const { text } = await agent.generate({
|
|
55
|
+
prompt: 'What is the weather in San Francisco?',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// => "San Francisco is sunny, about 68°F."
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
👉 See full working examples with [Vercel AI SDK](#with-vercel-ai-sdk), [OpenAI Agents SDK](#with-openai-agents-sdk), and [LangChain](#with-langchain).
|
|
62
|
+
|
|
63
|
+
<br>
|
|
64
|
+
|
|
65
|
+
## 🚀 Use Cases
|
|
66
|
+
|
|
67
|
+
| Prompt | Example Output |
|
|
68
|
+
| -------------------------------------------- | ------------------------------------------------ |
|
|
69
|
+
| `What is the weather in San Francisco?` | `San Francisco is sunny, about 68°F.` |
|
|
70
|
+
| `What time is it in Tokyo?` | `It's 3:42 PM JST.` |
|
|
71
|
+
| `When is the next Monday?` | `The next Monday is on February 10, 2025.` |
|
|
72
|
+
| `When is Thanksgiving next year?` | `Thanksgiving in 2026 falls on November 26.` |
|
|
73
|
+
| `How much is $250 in euros?` | `$250 equals €215.` |
|
|
74
|
+
| `Price of Apple stock?` | `Apple (AAPL) is trading at $175.20` |
|
|
75
|
+
| `Latest headlines about AI` | *Coming soon…* |
|
|
76
|
+
| `Who won the Lakers game last night?` | *Coming soon…* |
|
|
77
|
+
| `What's the current Bitcoin price?` | *Coming soon…* |
|
|
78
|
+
|
|
79
|
+
<br>
|
|
80
|
+
|
|
81
|
+
## 🥇 Key Features
|
|
82
|
+
|
|
83
|
+
- **Answers in <100ms** – Pre-cached data means your AI responds instantly, not after slow web searches
|
|
84
|
+
- **One tool, unlimited sources** – Weather, stocks, currency, and more through a single `lookup()` call
|
|
85
|
+
- **LLM-optimized responses** – Structured JSON designed for reasoning, not messy HTML to parse
|
|
86
|
+
- **Works everywhere** – Drop into Vercel AI SDK, OpenAI Agents, LangChain, or any framework
|
|
87
|
+
- **Zero configuration** – No API keys to juggle, no rate limits to manage, no parsers to write
|
|
88
|
+
- **Type-safe & predictable** – Full TypeScript support with discriminated unions for response types
|
|
89
|
+
- **Bring your own data** – Connect your databases and APIs for instant, grounded responses *(coming soon)*
|
|
90
|
+
|
|
91
|
+
<br>
|
|
92
|
+
|
|
93
|
+
## 💿 Installation
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pnpm add @neuledge/graph zod
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install @neuledge/graph zod
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
yarn add @neuledge/graph zod
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
<br>
|
|
108
|
+
|
|
109
|
+
## 📚 Examples
|
|
110
|
+
|
|
111
|
+
### With Vercel AI SDK
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
115
|
+
import { NeuledgeGraph } from "@neuledge/graph";
|
|
116
|
+
import { Experimental_Agent as Agent, stepCountIs, tool } from "ai";
|
|
117
|
+
|
|
118
|
+
const graph = new NeuledgeGraph();
|
|
119
|
+
|
|
120
|
+
const agent = new Agent({
|
|
121
|
+
model: anthropic("claude-sonnet-4-5"),
|
|
122
|
+
tools: {
|
|
123
|
+
lookup: tool(graph.lookup),
|
|
124
|
+
},
|
|
125
|
+
stopWhen: stepCountIs(20),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const { textStream } = agent.stream({
|
|
129
|
+
prompt: "Compare Apple and Microsoft stock prices",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
for await (const textPart of textStream) {
|
|
133
|
+
process.stdout.write(textPart);
|
|
134
|
+
}
|
|
135
|
+
process.stdout.write("\n");
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### With OpenAI Agents SDK
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { NeuledgeGraph } from "@neuledge/graph";
|
|
142
|
+
import { Agent, run, tool } from "@openai/agents";
|
|
143
|
+
|
|
144
|
+
const graph = new NeuledgeGraph();
|
|
145
|
+
|
|
146
|
+
const agent = new Agent({
|
|
147
|
+
name: "Data Assistant",
|
|
148
|
+
model: "gpt-4.1",
|
|
149
|
+
tools: [tool(graph.lookup)],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const result = await run(agent, "What is the current price of Apple stock?");
|
|
153
|
+
console.log(result);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### With LangChain
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// make sure to install all the following packages:
|
|
160
|
+
// $ npm install @neuledge/graph langchain @langchain/openai @langchain/core zod zod-to-json-schema
|
|
161
|
+
|
|
162
|
+
import { NeuledgeGraph } from "@neuledge/graph";
|
|
163
|
+
import { createAgent, tool } from "langchain";
|
|
164
|
+
|
|
165
|
+
// Create the tool from the graph lookup function
|
|
166
|
+
const graph = new NeuledgeGraph();
|
|
167
|
+
|
|
168
|
+
const lookup = tool(graph.lookup, graph.lookup);
|
|
169
|
+
|
|
170
|
+
// Create the agent with an OpenAI LLM
|
|
171
|
+
const agent = createAgent({
|
|
172
|
+
model: "openai:gpt-4.1",
|
|
173
|
+
tools: [lookup],
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Invoke the agent
|
|
177
|
+
const result = await agent.invoke({
|
|
178
|
+
messages: [
|
|
179
|
+
{ role: "user", content: "What is the exchange rate from USD to EUR?" },
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
console.log(result);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
<br>
|
|
186
|
+
|
|
187
|
+
## 🔐 Authentication & Rate Limits
|
|
188
|
+
|
|
189
|
+
By default, `@neuledge/graph` is free to use without authentication.
|
|
190
|
+
To increase your request limit, generate a **free API key**.
|
|
191
|
+
|
|
192
|
+
| Access Type | Requests Limit | Per-Minute Limit |
|
|
193
|
+
|--------------|-------------------|------------------|
|
|
194
|
+
| Anonymous | 100 / day | 5 requests/min |
|
|
195
|
+
| Free API Key | 10,000 / month | 60 requests/min |
|
|
196
|
+
| Pro Plan | *Coming soon* | *Coming soon* |
|
|
197
|
+
|
|
198
|
+
### Getting a Free API Key
|
|
199
|
+
|
|
200
|
+
Run the following command:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
npx @neuledge/graph sign-up your-email@example.com
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
You'll receive an API key via email:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
NEULEDGE_API_KEY='sk_xxxxxxxxx'
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Using Your API Key
|
|
213
|
+
|
|
214
|
+
Pass the key when initializing the graph:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import "dotenv/config";
|
|
218
|
+
import { NeuledgeGraph } from '@neuledge/graph';
|
|
219
|
+
|
|
220
|
+
const graph = new NeuledgeGraph({
|
|
221
|
+
apiKey: process.env.NEULEDGE_API_KEY
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Best Practice:** Store your API key in environment variables and never commit it to version control.
|
|
226
|
+
|
|
227
|
+
### Building a Custom Server
|
|
228
|
+
|
|
229
|
+
For advanced use cases, you can build your own knowledge graph server using the router and registry packages:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// Install: npm install @neuledge/graph-router @neuledge/graph-memory-registry fastify
|
|
233
|
+
import { NeuledgeGraphRouter } from "@neuledge/graph-router";
|
|
234
|
+
import { NeuledgeGraphMemoryRegistry } from "@neuledge/graph-memory-registry";
|
|
235
|
+
import { openai } from "ai";
|
|
236
|
+
import Fastify from "fastify";
|
|
237
|
+
|
|
238
|
+
// Create registry with embedding model
|
|
239
|
+
const registry = new NeuledgeGraphMemoryRegistry({
|
|
240
|
+
model: openai.embedding("text-embedding-3-small"),
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Register your data sources
|
|
244
|
+
await registry.register({
|
|
245
|
+
template: "cities.{city}.weather",
|
|
246
|
+
resolver: async (match) => {
|
|
247
|
+
const city = match.params.city;
|
|
248
|
+
const response = await fetch(`https://api.weather.com/current?city=${city}`);
|
|
249
|
+
return response.json();
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Create router
|
|
254
|
+
const router = new NeuledgeGraphRouter({ registry });
|
|
255
|
+
|
|
256
|
+
// Set up HTTP server
|
|
257
|
+
const app = Fastify();
|
|
258
|
+
|
|
259
|
+
app.post("/lookup", async (request, reply) => {
|
|
260
|
+
const result = await router.lookup(request.body);
|
|
261
|
+
return reply.send(result);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
app.listen({ port: 3000 });
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
See [graph-router](https://github.com/neuledge/graph/tree/main/packages/graph-router) and [graph-memory-registry](https://github.com/neuledge/graph/tree/main/packages/graph-memory-registry) packages for detailed documentation.
|
|
268
|
+
|
|
269
|
+
### Connecting to a Custom Server
|
|
270
|
+
|
|
271
|
+
Once you have a custom server running, connect to it using the `baseUrl` option:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { NeuledgeGraph } from "@neuledge/graph";
|
|
275
|
+
|
|
276
|
+
// Connect to your custom server
|
|
277
|
+
const graph = new NeuledgeGraph({
|
|
278
|
+
baseUrl: "http://localhost:3000",
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Use it the same way as with the default server
|
|
282
|
+
const result = await graph.lookup({ query: "cities.tokyo.weather" });
|
|
283
|
+
console.log(result); // => { status: "matched", match: {...}, value: {...} }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
You can now use this graph instance with any AI framework, and it will query your custom knowledge graph server instead of the default Neuledge service.
|
|
287
|
+
|
|
288
|
+
<br>
|
|
289
|
+
|
|
290
|
+
## 🛠 API Reference
|
|
291
|
+
|
|
292
|
+
### `NeuledgeGraph`
|
|
293
|
+
|
|
294
|
+
The main class for interacting with the knowledge graph.
|
|
295
|
+
|
|
296
|
+
#### Constructor Options
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
interface NeuledgeGraphOptions {
|
|
300
|
+
apiKey?: string; // Your API key (optional for free tier)
|
|
301
|
+
baseUrl?: string; // Custom API endpoint (optional)
|
|
302
|
+
timeout?: number; // Request timeout in ms (default: 10000)
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### Example
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
const graph = new NeuledgeGraph({
|
|
310
|
+
apiKey: process.env.NEULEDGE_API_KEY,
|
|
311
|
+
timeout: 5000,
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### `graph.lookup` Tool
|
|
316
|
+
|
|
317
|
+
The `lookup` tool is designed to be a **first-class tool** in any AI framework that supports function calling.
|
|
318
|
+
|
|
319
|
+
#### Properties
|
|
320
|
+
|
|
321
|
+
- **`lookup`** (`function`) – The function that fetches live data
|
|
322
|
+
- **`lookup.name`** (`string`) - The name of the tool (`"lookup"`)
|
|
323
|
+
- **`lookup.description`** (`string`) – Instructions for the LLM on how to use the tool
|
|
324
|
+
- **`lookup.parameters`** (`object`) – JSON Schema defining expected inputs
|
|
325
|
+
- **`lookup.execute`** (`function`) – same as calling `lookup` directly
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
<br>
|
|
329
|
+
|
|
330
|
+
## 🎯 Supported Data Sources
|
|
331
|
+
|
|
332
|
+
Currently available:
|
|
333
|
+
- ☀️ **Weather** - Current weather and forecasts for any location
|
|
334
|
+
- 💱 **Currency Exchange** - Live FX rates for 150+ currencies
|
|
335
|
+
- 📈 **Stock Market** - Current stock prices and market data
|
|
336
|
+
|
|
337
|
+
Coming soon:
|
|
338
|
+
- 📰 News & headlines
|
|
339
|
+
- ⚽ Sports scores & schedules
|
|
340
|
+
- 🪙 Cryptocurrency prices
|
|
341
|
+
- 🗺️ Geographic data
|
|
342
|
+
- 📊 Economic indicators
|
|
343
|
+
|
|
344
|
+
Want to request a data source? [Open an issue](https://github.com/neuledge/graph/issues/new)!
|
|
345
|
+
|
|
346
|
+
<br>
|
|
347
|
+
|
|
348
|
+
## Development Setup
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# Clone the repository
|
|
352
|
+
git clone https://github.com/neuledge/graph.git
|
|
353
|
+
cd graph
|
|
354
|
+
|
|
355
|
+
# Install dependencies
|
|
356
|
+
npm install
|
|
357
|
+
|
|
358
|
+
# Run tests
|
|
359
|
+
npm test
|
|
360
|
+
|
|
361
|
+
# Build the project
|
|
362
|
+
npm run build
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
<br>
|
|
366
|
+
|
|
367
|
+
## 📄 License
|
|
368
|
+
|
|
369
|
+
Apache-2.0 © Neuledge
|
|
370
|
+
|
|
371
|
+
See [LICENSE](LICENSE) for more information.
|
|
372
|
+
|
|
373
|
+
<br>
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
<div align="center">
|
|
378
|
+
|
|
379
|
+
**Built with ❤️ by Neuledge**
|
|
380
|
+
|
|
381
|
+
</div>
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const [, , command, ...args] = process.argv;
|
|
4
|
+
|
|
5
|
+
const NEULEDGE_API_BASE_URL = "https://api.graph.neuledge.com/v1";
|
|
6
|
+
|
|
7
|
+
(async () => {
|
|
8
|
+
try {
|
|
9
|
+
switch (command) {
|
|
10
|
+
case "sign-up": {
|
|
11
|
+
const email = args[0];
|
|
12
|
+
if (!email) {
|
|
13
|
+
console.error("Usage: sign-up <email>");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
console.log("Signing up…");
|
|
18
|
+
|
|
19
|
+
const result = await signUp(email);
|
|
20
|
+
|
|
21
|
+
console.log("✅ Signed up successfully");
|
|
22
|
+
if (result?.message) {
|
|
23
|
+
console.log(result.message);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
case undefined:
|
|
30
|
+
case "help":
|
|
31
|
+
printHelp();
|
|
32
|
+
break;
|
|
33
|
+
|
|
34
|
+
default:
|
|
35
|
+
console.error(`Unknown command: ${command}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error("❌", err.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
|
|
44
|
+
function printHelp() {
|
|
45
|
+
console.log(`
|
|
46
|
+
Usage:
|
|
47
|
+
graph sign-up <email>
|
|
48
|
+
|
|
49
|
+
Commands:
|
|
50
|
+
sign-up Register an email
|
|
51
|
+
help Showing this message
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
graph sign-up your@email.com
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function signUp(email) {
|
|
59
|
+
if (!email.includes("@")) {
|
|
60
|
+
throw new TypeError("Invalid email address");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const controller = new AbortController();
|
|
64
|
+
setTimeout(() => controller.abort(), 10_000);
|
|
65
|
+
|
|
66
|
+
const res = await fetch(`${NEULEDGE_API_BASE_URL}/cli/sign-up`, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({ email }),
|
|
72
|
+
abort: controller.signal,
|
|
73
|
+
}).catch(() => {
|
|
74
|
+
throw new Error("Error while accessing the server");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
const text = await res
|
|
79
|
+
.json()
|
|
80
|
+
.then((body) => {
|
|
81
|
+
const message = body?.error?.message;
|
|
82
|
+
if (!message) {
|
|
83
|
+
throw new Error("Invalid error format");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return message;
|
|
87
|
+
})
|
|
88
|
+
.catch(() => res.text());
|
|
89
|
+
throw new Error(`Sign-up failed (${res.status}): ${text}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return res.json();
|
|
93
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NeuledgeError } from "./error.js";
|
|
2
|
+
import type { NeuledgeGraph } from "./index.js";
|
|
3
|
+
export interface ApiFetchParams {
|
|
4
|
+
method?: "GET" | "POST" | "PUT" | "DELETE";
|
|
5
|
+
url: string;
|
|
6
|
+
body?: object;
|
|
7
|
+
}
|
|
8
|
+
export interface NeuledgeApiErrorResponse {
|
|
9
|
+
error: NeuledgeError;
|
|
10
|
+
}
|
|
11
|
+
export declare function apiFetch<T>(graph: NeuledgeGraph, params: ApiFetchParams): Promise<T>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { NeuledgeError } from "./error.js";
|
|
2
|
+
export async function apiFetch(graph, params) {
|
|
3
|
+
const url = `${graph.baseUrl}${params.url}`;
|
|
4
|
+
const headers = {
|
|
5
|
+
"Content-Type": "application/json",
|
|
6
|
+
};
|
|
7
|
+
if (graph.apiKey)
|
|
8
|
+
headers.Authorization = `Bearer ${graph.apiKey}`;
|
|
9
|
+
const res = await fetch(url, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers,
|
|
12
|
+
body: params.body ? JSON.stringify(params.body) : undefined,
|
|
13
|
+
});
|
|
14
|
+
if (!res.ok) {
|
|
15
|
+
return res
|
|
16
|
+
.json()
|
|
17
|
+
.then((data) => {
|
|
18
|
+
const typed = data;
|
|
19
|
+
if (typeof typed?.error?.message !== "string") {
|
|
20
|
+
throw new Error(`Unknown error response`);
|
|
21
|
+
}
|
|
22
|
+
throw new NeuledgeError(typed.error.message);
|
|
23
|
+
})
|
|
24
|
+
.catch(() => {
|
|
25
|
+
throw new NeuledgeError(`NeuledgeGraph: Request failed with ${res.statusText}`);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const data = await res.json();
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=api-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-fetch.js","sourceRoot":"","sources":["../src/api-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAa3C,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,KAAoB,EACpB,MAAsB;IAEtB,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;IAC5C,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAC;IACF,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,CAAC,aAAa,GAAG,UAAU,KAAK,CAAC,MAAM,EAAE,CAAC;IAEnE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,MAAM;QACd,OAAO;QACP,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KAC5D,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO,GAAG;aACP,IAAI,EAAE;aACN,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,MAAM,KAAK,GAAG,IAAyC,CAAC;YACxD,IAAI,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC9C,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAC5C,CAAC;YAED,MAAM,IAAI,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,MAAM,IAAI,aAAa,CACrB,sCAAsC,GAAG,CAAC,UAAU,EAAE,CACvD,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,OAAO,IAAS,CAAC;AACnB,CAAC"}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface NeuledgeError {
|
|
2
|
+
message: string;
|
|
3
|
+
}
|
|
4
|
+
declare class NeuledgeErrorImpl extends Error implements NeuledgeError {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
static from(error: NeuledgeError | unknown): NeuledgeError;
|
|
7
|
+
}
|
|
8
|
+
export declare const NeuledgeError: typeof NeuledgeErrorImpl;
|
|
9
|
+
export {};
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class NeuledgeErrorImpl extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "NeuledgeError";
|
|
5
|
+
// Maintain proper prototype chain for instanceof checks
|
|
6
|
+
Object.setPrototypeOf(this, NeuledgeError.prototype);
|
|
7
|
+
}
|
|
8
|
+
static from(error) {
|
|
9
|
+
if (error instanceof NeuledgeError) {
|
|
10
|
+
return error;
|
|
11
|
+
}
|
|
12
|
+
const message = String(error?.message || error);
|
|
13
|
+
const neuledgeError = new NeuledgeError(message);
|
|
14
|
+
// Preserve the original stack trace if available
|
|
15
|
+
const stack = error?.stack;
|
|
16
|
+
if (stack)
|
|
17
|
+
neuledgeError.stack = stack;
|
|
18
|
+
return neuledgeError;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export const NeuledgeError = NeuledgeErrorImpl;
|
|
22
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAIA,MAAM,iBAAkB,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAE5B,wDAAwD;QACxD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,KAA8B;QACxC,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAE,KAAuB,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;QACnE,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;QAEjD,iDAAiD;QACjD,MAAM,KAAK,GAAI,KAAe,EAAE,KAAK,CAAC;QACtC,IAAI,KAAK;YAAE,aAAa,CAAC,KAAK,GAAG,KAAK,CAAC;QAEvC,OAAO,aAAa,CAAC;IACvB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,iBAAiB,CAAC"}
|
package/dist/graph.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { lookup } from "./lookup.js";
|
|
2
|
+
export interface NeuledgeGraphOptions {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class NeuledgeGraph {
|
|
8
|
+
apiKey?: string;
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
timeout: number;
|
|
11
|
+
constructor(options?: NeuledgeGraphOptions);
|
|
12
|
+
lookup: typeof lookup;
|
|
13
|
+
}
|
package/dist/graph.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { lookup } from "./lookup.js";
|
|
2
|
+
export class NeuledgeGraph {
|
|
3
|
+
apiKey;
|
|
4
|
+
baseUrl;
|
|
5
|
+
timeout;
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.apiKey = options.apiKey;
|
|
8
|
+
this.baseUrl = options.baseUrl || "https://api.graph.neuledge.com/v1";
|
|
9
|
+
this.timeout = options.timeout || 10000;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
NeuledgeGraph.prototype.lookup = lookup;
|
|
13
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,MAAM,OAAO,aAAa;IACxB,MAAM,CAAU;IAChB,OAAO,CAAS;IAChB,OAAO,CAAS;IAEhB,YAAY,UAAgC,EAAE;QAC5C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,mCAAmC,CAAC;QACtE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;IAC1C,CAAC;CAIF;AAED,aAAa,CAAC,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { NeuledgeApiErrorResponse } from "./api-fetch.js";
|
|
2
|
+
export { NeuledgeError } from "./error.js";
|
|
3
|
+
export { NeuledgeGraph, type NeuledgeGraphOptions } from "./graph.js";
|
|
4
|
+
export { type NeuledgeGraphLookup, type NeuledgeGraphLookupAmbiguousResponse, type NeuledgeGraphLookupErrorResponse, type NeuledgeGraphLookupMatchedResponse, NeuledgeGraphLookupParams, type NeuledgeGraphLookupResponse, type NeuledgeGraphLookupResponseTemplate, } from "./lookup.js";
|
|
5
|
+
export type { NeuledgeGraphMatch, NeuledgeGraphTemplateParams, } from "./match.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,aAAa,EAA6B,MAAM,YAAY,CAAC;AACtE,OAAO,EAKL,yBAAyB,GAG1B,MAAM,aAAa,CAAC"}
|
package/dist/lookup.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { NeuledgeError } from "./error.js";
|
|
3
|
+
import type { NeuledgeGraph } from "./index.js";
|
|
4
|
+
export interface NeuledgeGraphLookup {
|
|
5
|
+
(this: NeuledgeGraph, params: NeuledgeGraphLookupParams): Promise<NeuledgeGraphLookupResponse | NeuledgeGraphLookupErrorResponse>;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
parameters: typeof NeuledgeGraphLookupParams;
|
|
9
|
+
schema: typeof NeuledgeGraphLookupParams;
|
|
10
|
+
inputSchema: typeof NeuledgeGraphLookupParams;
|
|
11
|
+
execute: NeuledgeGraphLookup;
|
|
12
|
+
}
|
|
13
|
+
export type NeuledgeGraphLookupParams = z.infer<typeof NeuledgeGraphLookupParams>;
|
|
14
|
+
export declare const NeuledgeGraphLookupParams: z.ZodObject<{
|
|
15
|
+
query: z.ZodString;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type NeuledgeGraphLookupResponse = NeuledgeGraphLookupMatchedResponse | NeuledgeGraphLookupAmbiguousResponse;
|
|
18
|
+
export interface NeuledgeGraphLookupMatchedResponse<T = unknown> {
|
|
19
|
+
status: "matched";
|
|
20
|
+
match: NeuledgeGraphLookupResponseTemplate;
|
|
21
|
+
value: T;
|
|
22
|
+
}
|
|
23
|
+
export interface NeuledgeGraphLookupAmbiguousResponse {
|
|
24
|
+
status: "ambiguous";
|
|
25
|
+
reasonCode: "UNKNOWN_PATH" | "INVALID_IDENTIFIER" | (string & {});
|
|
26
|
+
reasonHint: string;
|
|
27
|
+
suggestions: NeuledgeGraphLookupResponseTemplate[];
|
|
28
|
+
}
|
|
29
|
+
export interface NeuledgeGraphLookupResponseTemplate {
|
|
30
|
+
template: string;
|
|
31
|
+
}
|
|
32
|
+
export interface NeuledgeGraphLookupErrorResponse {
|
|
33
|
+
status: "error";
|
|
34
|
+
error: NeuledgeError;
|
|
35
|
+
}
|
|
36
|
+
export declare const lookup: NeuledgeGraphLookup;
|
package/dist/lookup.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { apiFetch } from "./api-fetch.js";
|
|
3
|
+
import { NeuledgeError } from "./error.js";
|
|
4
|
+
const description = `This tool provides access to **live, structured data** across a wide range of domains.
|
|
5
|
+
|
|
6
|
+
It ensures answers are **accurate and up-to-date**, preventing the model from relying on outdated information or hallucinating (e.g., old stock prices, past weather, or obsolete events).
|
|
7
|
+
|
|
8
|
+
Queries should use **\`snake_case\`** with dots between segments (\`lowercase.with_underscores\`).
|
|
9
|
+
|
|
10
|
+
The system tries to match your query to a **built-in template** and fill the \`{placeholders}\`.
|
|
11
|
+
|
|
12
|
+
* If a close template exists, you receive the structured data.
|
|
13
|
+
* If no exact match, the system returns **suggested templates** you can refine your query against.
|
|
14
|
+
|
|
15
|
+
**This tool supports many domains including (but not limited to):**
|
|
16
|
+
- Weather, time, and location data
|
|
17
|
+
- Financial data (stocks, currencies, markets)
|
|
18
|
+
- Calendar operations and holidays
|
|
19
|
+
- And many other live data sources
|
|
20
|
+
|
|
21
|
+
**The most popular templates used:**
|
|
22
|
+
* \`cities.{city}.weather\`
|
|
23
|
+
* \`cities.{city}.time\`
|
|
24
|
+
* \`stocks.{stock}.quote\`
|
|
25
|
+
* \`currencies.{from}.rate.{to}\`
|
|
26
|
+
* \`calendar.next.{weekday}\`
|
|
27
|
+
* \`calendar.in.{integer}.{unit}\`
|
|
28
|
+
* \`holidays.{holiday}.next\`
|
|
29
|
+
|
|
30
|
+
**Key principle:** Even if your query doesn't exactly match a template, the tool will **suggest the closest available templates**, allowing you to refine and retrieve the live data. When in doubt, try a query - the tool will guide you to the right template.`;
|
|
31
|
+
export const NeuledgeGraphLookupParams = z.object({
|
|
32
|
+
query: z
|
|
33
|
+
.string()
|
|
34
|
+
.describe(`A search query using snake_case and dots between segments (lowercase.with_underscores).`),
|
|
35
|
+
// context: z
|
|
36
|
+
// .object({
|
|
37
|
+
// units: z
|
|
38
|
+
// .enum(["auto", "metric", "imperial"])
|
|
39
|
+
// .default("auto")
|
|
40
|
+
// .describe(
|
|
41
|
+
// "Measurement system for applicable data (temperature, distance, etc.). 'auto' uses location-appropriate defaults.",
|
|
42
|
+
// )
|
|
43
|
+
// .optional(),
|
|
44
|
+
//
|
|
45
|
+
// date: z
|
|
46
|
+
// .string()
|
|
47
|
+
// .regex(/^\d{4}-\d{2}-\d{2}$/, "Must be YYYY-MM-DD format")
|
|
48
|
+
// .describe(
|
|
49
|
+
// "Reference date for time-sensitive queries. Defaults to current date if not specified.",
|
|
50
|
+
// )
|
|
51
|
+
// .optional(),
|
|
52
|
+
//
|
|
53
|
+
// amount: z
|
|
54
|
+
// .number()
|
|
55
|
+
// .positive()
|
|
56
|
+
// .describe(
|
|
57
|
+
// "Quantity for conversion queries (e.g., currency amounts). Defaults to 1 if not specified.",
|
|
58
|
+
// )
|
|
59
|
+
// .optional(),
|
|
60
|
+
//
|
|
61
|
+
// timezone: z
|
|
62
|
+
// .string()
|
|
63
|
+
// .regex(
|
|
64
|
+
// /^([A-Z]{2,5}|[A-Za-z]+\/[A-Za-z_]+)$/,
|
|
65
|
+
// "Must be a valid timezone (e.g., 'EST', 'America/New_York')",
|
|
66
|
+
// )
|
|
67
|
+
// .describe(
|
|
68
|
+
// "TTimezone for date/time queries (e.g., 'America/New_York', 'EST')",
|
|
69
|
+
// )
|
|
70
|
+
// .optional(),
|
|
71
|
+
//
|
|
72
|
+
// locale: z
|
|
73
|
+
// .string()
|
|
74
|
+
// .regex(
|
|
75
|
+
// /^[a-z]{2}(-[A-Z]{2})?$/,
|
|
76
|
+
// "Must be language code or language-country (e.g., 'en', 'en-US')",
|
|
77
|
+
// )
|
|
78
|
+
// .describe(
|
|
79
|
+
// "Locale for formatting numbers, dates, and currency. Affects output presentation.",
|
|
80
|
+
// )
|
|
81
|
+
// .optional(),
|
|
82
|
+
// })
|
|
83
|
+
// .describe(
|
|
84
|
+
// "Optional parameters that modify how data is retrieved or formatted.",
|
|
85
|
+
// )
|
|
86
|
+
// .optional(),
|
|
87
|
+
});
|
|
88
|
+
export const lookup = Object.assign(async function lookup(params) {
|
|
89
|
+
return await apiFetch(this, {
|
|
90
|
+
url: "/lookup",
|
|
91
|
+
method: "POST",
|
|
92
|
+
body: {
|
|
93
|
+
query: params.query,
|
|
94
|
+
// context: params.context,
|
|
95
|
+
},
|
|
96
|
+
}).catch((error) => ({
|
|
97
|
+
status: "error",
|
|
98
|
+
error: NeuledgeError.from(error),
|
|
99
|
+
}));
|
|
100
|
+
}, {
|
|
101
|
+
description,
|
|
102
|
+
parameters: NeuledgeGraphLookupParams,
|
|
103
|
+
schema: NeuledgeGraphLookupParams,
|
|
104
|
+
inputSchema: NeuledgeGraphLookupParams,
|
|
105
|
+
execute: null,
|
|
106
|
+
});
|
|
107
|
+
// force `name` property to be enumerable (fix LangChain bug)
|
|
108
|
+
Object.defineProperty(lookup, "name", { value: "lookup", enumerable: true });
|
|
109
|
+
// self assign `execute`
|
|
110
|
+
lookup.execute = lookup;
|
|
111
|
+
//# sourceMappingURL=lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup.js","sourceRoot":"","sources":["../src/lookup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAiB3C,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;kQA0B8O,CAAC;AAKnQ,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,CACP,yFAAyF,CAC1F;IAEH,eAAe;IACf,gBAAgB;IAChB,iBAAiB;IACjB,gDAAgD;IAChD,2BAA2B;IAC3B,qBAAqB;IACrB,gIAAgI;IAChI,YAAY;IACZ,uBAAuB;IACvB,EAAE;IACF,gBAAgB;IAChB,oBAAoB;IACpB,qEAAqE;IACrE,qBAAqB;IACrB,qGAAqG;IACrG,YAAY;IACZ,uBAAuB;IACvB,EAAE;IACF,kBAAkB;IAClB,oBAAoB;IACpB,sBAAsB;IACtB,qBAAqB;IACrB,yGAAyG;IACzG,YAAY;IACZ,uBAAuB;IACvB,EAAE;IACF,oBAAoB;IACpB,oBAAoB;IACpB,kBAAkB;IAClB,oDAAoD;IACpD,0EAA0E;IAC1E,YAAY;IACZ,qBAAqB;IACrB,iFAAiF;IACjF,YAAY;IACZ,uBAAuB;IACvB,EAAE;IACF,kBAAkB;IAClB,oBAAoB;IACpB,kBAAkB;IAClB,sCAAsC;IACtC,+EAA+E;IAC/E,YAAY;IACZ,qBAAqB;IACrB,gGAAgG;IAChG,YAAY;IACZ,uBAAuB;IACvB,SAAS;IACT,iBAAiB;IACjB,+EAA+E;IAC/E,QAAQ;IACR,mBAAmB;CACpB,CAAC,CAAC;AA4BH,MAAM,CAAC,MAAM,MAAM,GAAwB,MAAM,CAAC,MAAM,CACtD,KAAK,UAAU,MAAM,CAEnB,MAAiC;IAEjC,OAAO,MAAM,QAAQ,CAA8B,IAAI,EAAE;QACvD,GAAG,EAAE,SAAS;QACd,MAAM,EAAE,MAAM;QACd,IAAI,EAAE;YACJ,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,2BAA2B;SACQ;KACtC,CAAC,CAAC,KAAK,CACN,CAAC,KAAK,EAAoC,EAAE,CAAC,CAAC;QAC5C,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;KACjC,CAAC,CACH,CAAC;AACJ,CAAC,EACD;IACE,WAAW;IACX,UAAU,EAAE,yBAAyB;IACrC,MAAM,EAAE,yBAAyB;IACjC,WAAW,EAAE,yBAAyB;IACtC,OAAO,EAAE,IAAa;CACvB,CACF,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;AAE7E,wBAAwB;AACxB,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC"}
|
package/dist/match.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface NeuledgeGraphMatch<Template extends string = string> {
|
|
2
|
+
template: Template;
|
|
3
|
+
params: NeuledgeGraphTemplateParams<Template>;
|
|
4
|
+
}
|
|
5
|
+
export type NeuledgeGraphTemplateParams<Template extends string = string> = Record<NeuledgeGraphTemplateParamsNames<Template>, string>;
|
|
6
|
+
type NeuledgeGraphTemplateParamsNames<T extends string> = T extends `${string}{${infer Param}}${infer Rest}` ? Param | NeuledgeGraphTemplateParamsNames<Rest> : never;
|
|
7
|
+
export {};
|
package/dist/match.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@neuledge/graph",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Give LLMs real knowledge — structured, live, and reliable — so they reason with facts, not guesses.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"llm",
|
|
8
|
+
"agents",
|
|
9
|
+
"openai",
|
|
10
|
+
"anthropic",
|
|
11
|
+
"langchain",
|
|
12
|
+
"vercel-ai",
|
|
13
|
+
"ai-sdk",
|
|
14
|
+
"tool",
|
|
15
|
+
"function-calling",
|
|
16
|
+
"structured-data",
|
|
17
|
+
"live-data",
|
|
18
|
+
"knowledge-graph",
|
|
19
|
+
"real-time-data",
|
|
20
|
+
"data-fetching",
|
|
21
|
+
"ai-integration",
|
|
22
|
+
"ai-tools",
|
|
23
|
+
"lookup",
|
|
24
|
+
"grounding",
|
|
25
|
+
"no-rag",
|
|
26
|
+
"no-indexes",
|
|
27
|
+
"json-api",
|
|
28
|
+
"data-layer",
|
|
29
|
+
"ai-infrastructure",
|
|
30
|
+
"neuledge",
|
|
31
|
+
"weather",
|
|
32
|
+
"stocks",
|
|
33
|
+
"price",
|
|
34
|
+
"fx",
|
|
35
|
+
"rates"
|
|
36
|
+
],
|
|
37
|
+
"main": "dist/index.js",
|
|
38
|
+
"types": "dist/index.d.ts",
|
|
39
|
+
"type": "module",
|
|
40
|
+
"exports": {
|
|
41
|
+
".": "./dist/index.js"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/",
|
|
45
|
+
"bin/",
|
|
46
|
+
"package.json",
|
|
47
|
+
"README.md",
|
|
48
|
+
"LICENSE"
|
|
49
|
+
],
|
|
50
|
+
"bin": "./bin/cli.js",
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"author": "Neuledge",
|
|
55
|
+
"license": "Apache-2.0",
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@ai-sdk/anthropic": "^2.0.50",
|
|
58
|
+
"@ai-sdk/openai": "^2.0.74",
|
|
59
|
+
"@langchain/core": "^1.0.1",
|
|
60
|
+
"@langchain/openai": "^1.0.0",
|
|
61
|
+
"@openai/agents": "^0.2.1",
|
|
62
|
+
"@total-typescript/tsconfig": "^1.0.4",
|
|
63
|
+
"@types/js-yaml": "^4.0.9",
|
|
64
|
+
"@types/node": "^24.9.1",
|
|
65
|
+
"ai": "^5.0.104",
|
|
66
|
+
"dotenv": "^17.2.3",
|
|
67
|
+
"js-yaml": "^4.1.1",
|
|
68
|
+
"langchain": "^1.0.1",
|
|
69
|
+
"rimraf": "^6.0.1",
|
|
70
|
+
"tsconfig-paths": "^4.2.0",
|
|
71
|
+
"tsx": "^4.20.6",
|
|
72
|
+
"typescript": "^5.9.3",
|
|
73
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
74
|
+
"vitest": "^4.0.3",
|
|
75
|
+
"zod": "^4.2.1",
|
|
76
|
+
"zod-to-json-schema": "^3.24.6"
|
|
77
|
+
},
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"zod": ">=3"
|
|
80
|
+
},
|
|
81
|
+
"tsx": {
|
|
82
|
+
"require": [
|
|
83
|
+
"tsconfig-paths/register"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
"scripts": {
|
|
87
|
+
"build": "rimraf --glob dist/** && tsc -p tsconfig.build.json",
|
|
88
|
+
"test": "vitest run",
|
|
89
|
+
"test:watch": "vitest",
|
|
90
|
+
"evals": "vitest run --config vitest.config.evals.ts",
|
|
91
|
+
"lint": "npx biome ci --error-on-warnings",
|
|
92
|
+
"fix": "npx biome check --write"
|
|
93
|
+
}
|
|
94
|
+
}
|