@north-light/cli 0.3.478 → 0.3.479
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/dist/builtin-memory/northlight-apps/coding-agents.md +1 -1
- package/dist/builtin-memory/northlight-apps/concepts/runs.md +5 -3
- package/dist/builtin-memory/northlight-apps/quickstart.md +8 -5
- package/docs/apps/coding-agents.md +1 -1
- package/docs/apps/concepts/runs.md +2 -2
- package/docs/apps/quickstart.md +3 -3
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +15 -12
|
@@ -39,7 +39,7 @@ npx @north-light/sdk skill
|
|
|
39
39
|
|
|
40
40
|
The project copy is the default so it is committed with the project, and teammates get it from git. It matches the SDK version your project pins.
|
|
41
41
|
|
|
42
|
-
Checked on production: the files `init` writes, that `init` in a directory that already has a `package.json` pins the SDK and writes the key and skill but no app code, and that `skill` rewrites both skill files.
|
|
42
|
+
Checked on production: the files `init` writes, that `init` in a directory that already has a `package.json` pins the SDK and writes the key and skill but no app code, and that `skill` rewrites both skill files. In such a directory `init` creates a `.gitignore` with `local/`, or adds `local/` to the one you have, so the key stays out of git. Which agent loads which directory is from each agent's documentation and is not yet checked on production for every agent.
|
|
43
43
|
|
|
44
44
|
## Without a project: the hosted skill
|
|
45
45
|
|
|
@@ -12,11 +12,13 @@ A run is an agent that works on a person's Northlight runtime, on your behalf an
|
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
const runtime = await oauth.client(userId); // a client on this person's runtime, from their stored connection
|
|
15
|
-
|
|
15
|
+
// The prompt is the instruction; the message stored with it joins the first turn, so `reply` can follow that turn.
|
|
16
|
+
const started = await runtime.runs.start({prompt: 'Reply with exactly the word: pong', message: 'ping', scopes: ['crtr:llm', 'crtr:act']});
|
|
17
|
+
const reply = await runtime.runs.reply(started.run_id, started.message!).collect(); // reply.text is what the agent said
|
|
16
18
|
const run = await runtime.runs.wait(started.run_id); // status is 'idle' once the reply is done
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
`runs.start` returns at once with a `run_id`. `runs.wait(runId)` long-polls until the run is no longer `running`.
|
|
21
|
+
`runs.start` returns at once with a `run_id`. Passing `message` stores a first message with the run, and `runs.reply(runId, started.message)` follows the turn that answers it (`collect()` gives its `text`). `runs.wait(runId)` long-polls until the run is no longer `running`.
|
|
20
22
|
|
|
21
23
|
## Status
|
|
22
24
|
|
|
@@ -43,7 +45,7 @@ A `settled` run has an `outcome`:
|
|
|
43
45
|
| `deadline_exceeded` | A deadline ended it. |
|
|
44
46
|
| `runtime_error` | The runtime failed. `details.crouter_reason` says why. |
|
|
45
47
|
|
|
46
|
-
`last_report` is the agent
|
|
48
|
+
A run that is only `idle` has no `outcome`. Read what the agent said from `runs.reply(...).collect()`. `last_report` is present only if the agent pushed a report. To get data back, give the run an `output_schema` and read it with `runs.parse`: see [[northlight-apps/guides/typed-results]]. Do not parse the assistant's text out of `runs.trace`. The trace is what the model said, not a value anything checked.
|
|
47
49
|
|
|
48
50
|
## Scopes
|
|
49
51
|
|
|
@@ -13,7 +13,7 @@ npx @north-light/sdk@latest init my-app
|
|
|
13
13
|
|
|
14
14
|
This command creates a small Node server, a signing key and an env file. About ten minutes later you have an app on your laptop that signs you in with Northlight, starts an agent run on your own Northlight runtime, and texts your phone. The app runs on your machine and talks to Northlight's production directory at `https://account.northlight.ai`. There is no local Northlight stack to run, and you do not need crouter.
|
|
15
15
|
|
|
16
|
-
You need Node.js
|
|
16
|
+
You need Node.js 20.6 or later (the start command uses `--env-file`) and a phone that can receive iMessage. The server was run on Node 20.6, 20.20, 22.14, 22.22 and 26.12.
|
|
17
17
|
|
|
18
18
|
Using a coding agent? Run the same `init` command, or tell your agent: *Read https://sdk.docs.northlight.ai/SKILL.md and follow it.* See [[northlight-apps/coding-agents]].
|
|
19
19
|
|
|
@@ -109,9 +109,9 @@ node --env-file=local/app.env --import tsx server.ts
|
|
|
109
109
|
|
|
110
110
|
(`npm start` runs the same command.) You should see `Listening on http://localhost:3000`.
|
|
111
111
|
|
|
112
|
-
Open `http://localhost:3000/auth/login`. Your browser goes to `account.northlight.ai`. Sign in if asked, read the consent page, and choose Allow. You land back on `http://localhost:3000/` with "Signed in" and your Northlight user id. Press **Start a run and send me a text**. The page answers "Done", shows the run's status `idle
|
|
112
|
+
Open `http://localhost:3000/auth/login`. Your browser goes to `account.northlight.ai`. Sign in if asked, read the consent page, and choose Allow. You land back on `http://localhost:3000/` with "Signed in" and your Northlight user id. Press **Start a run and send me a text**. The page answers "Done", shows the run's status `idle`, the run's reply (`pong`) and the text's `message_id`, and your phone receives "Hello from my first Northlight app." from Northlight's number.
|
|
113
113
|
|
|
114
|
-
Checked on production, as the account that owns the app: the server starts (with `npm start` too), `/` shows the sign-in link, and `/auth/login` answers `303` to `https://account.northlight.ai/authorize?client_id=…&scope=openid+profile+crtr%3Allm+crtr%3Aact+sms%3Asend…&code_challenge_method=S256…`. The consent page listed the four permissions and the monthly cap, **Allow** returned to `http://localhost:3000/` with "Signed in" and the user id, and the button page answered "Done" with status `idle` and a `message_id` for the text. In the console the key then read "Last used just now". Not yet checked on production: that the text reached the phone (the `message_id` is the provider's answer, not a delivery receipt),
|
|
114
|
+
Checked on production, as the account that owns the app: the server starts (with `npm start` too), `/` shows the sign-in link, and `/auth/login` answers `303` to `https://account.northlight.ai/authorize?client_id=…&scope=openid+profile+crtr%3Allm+crtr%3Aact+sms%3Asend…&code_challenge_method=S256…`. The consent page listed the four permissions and the monthly cap, **Allow** returned to `http://localhost:3000/` with "Signed in" and the user id, and the button page answered "Done" with status `idle` and a `message_id` for the text. In the console the key then read "Last used just now". Not yet checked on production: that the text reached the phone (the `message_id` is the provider's answer, not a delivery receipt), and the `426` case. The `pong` reply is read through `runs.reply` and has not been run on production since this example changed. Signing in as a second person needs a second account and is not covered here.
|
|
115
115
|
|
|
116
116
|
If `/` shows "One step left", `CROUTER_CLIENT_ID` is empty: repeat step 5 and restart. If a call fails with `426 runtime_version_unsupported`, your SDK is newer than the Northlight runtimes. Install the previous version with `npm i --save-exact @north-light/sdk@<version>` and tell support@northlight.ai.
|
|
117
117
|
|
|
@@ -193,11 +193,14 @@ const server = createServer(async (req, res) => {
|
|
|
193
193
|
|
|
194
194
|
if (url.pathname === '/run' && req.method === 'POST') {
|
|
195
195
|
const runtime = await oauth.client(userId); // a client on this person's runtime, from their stored connection
|
|
196
|
-
|
|
196
|
+
// The prompt is the instruction; the message stored with it joins the first turn, so `reply` can follow that turn.
|
|
197
|
+
const started = await runtime.runs.start({prompt: 'Reply with exactly the word: pong', message: 'ping', scopes: ['crtr:llm', 'crtr:act']});
|
|
198
|
+
const reply = await runtime.runs.reply(started.run_id, started.message!).collect(); // reply.text is what the agent said
|
|
197
199
|
const run = await runtime.runs.wait(started.run_id); // status is 'idle' once the reply is done
|
|
198
200
|
// Texts the signed-in person's own verified phone through the sms provider (50 per person per UTC day).
|
|
199
201
|
const sent = await runtime.providers.call({provider: 'sms', tool: 'send', arguments: {body: 'Hello from my first Northlight app.'}});
|
|
200
|
-
|
|
202
|
+
const {message_id} = sent as {message_id: string}; // the provider also returns a note meant for agents; it is not shown here
|
|
203
|
+
return page(res, 200, `<h1>Done</h1><p>The run finished with status <code>${escapeHtml(run.status)}</code> and replied <code>${escapeHtml(reply.text)}</code>. A text is on its way to your phone.</p><pre>${escapeHtml(JSON.stringify({run: run.run_id, status: run.status, reply: reply.text, message_id}, null, 2))}</pre><p><a href="/">Back</a></p>`);
|
|
201
204
|
}
|
|
202
205
|
return page(res, 200, `<h1>Signed in</h1><p>You are <code>${escapeHtml(userId)}</code>.</p><form method="post" action="/run"><button>Start a run and send me a text</button></form>`);
|
|
203
206
|
} catch (error) {
|
|
@@ -36,7 +36,7 @@ npx @north-light/sdk skill
|
|
|
36
36
|
|
|
37
37
|
The project copy is the default so it is committed with the project, and teammates get it from git. It matches the SDK version your project pins.
|
|
38
38
|
|
|
39
|
-
Checked on production: the files `init` writes, that `init` in a directory that already has a `package.json` pins the SDK and writes the key and skill but no app code, and that `skill` rewrites both skill files.
|
|
39
|
+
Checked on production: the files `init` writes, that `init` in a directory that already has a `package.json` pins the SDK and writes the key and skill but no app code, and that `skill` rewrites both skill files. In such a directory `init` creates a `.gitignore` with `local/`, or adds `local/` to the one you have, so the key stays out of git. Which agent loads which directory is from each agent's documentation and is not yet checked on production for every agent.
|
|
40
40
|
|
|
41
41
|
## Without a project: the hosted skill
|
|
42
42
|
|
|
@@ -9,7 +9,7 @@ A run is an agent that works on a person's Northlight runtime, on your behalf an
|
|
|
9
9
|
|
|
10
10
|
<include lang="ts">../../../examples/apps/quickstart-server.ts#run</include>
|
|
11
11
|
|
|
12
|
-
`runs.start` returns at once with a `run_id`. `runs.wait(runId)` long-polls until the run is no longer `running`.
|
|
12
|
+
`runs.start` returns at once with a `run_id`. Passing `message` stores a first message with the run, and `runs.reply(runId, started.message)` follows the turn that answers it (`collect()` gives its `text`). `runs.wait(runId)` long-polls until the run is no longer `running`.
|
|
13
13
|
|
|
14
14
|
## Status
|
|
15
15
|
|
|
@@ -36,7 +36,7 @@ A `settled` run has an `outcome`:
|
|
|
36
36
|
| `deadline_exceeded` | A deadline ended it. |
|
|
37
37
|
| `runtime_error` | The runtime failed. `details.crouter_reason` says why. |
|
|
38
38
|
|
|
39
|
-
`last_report` is the agent
|
|
39
|
+
A run that is only `idle` has no `outcome`. Read what the agent said from `runs.reply(...).collect()`. `last_report` is present only if the agent pushed a report. To get data back, give the run an `output_schema` and read it with `runs.parse`: see [Typed results](/docs/guides/typed-results). Do not parse the assistant's text out of `runs.trace`. The trace is what the model said, not a value anything checked.
|
|
40
40
|
|
|
41
41
|
## Scopes
|
|
42
42
|
|
package/docs/apps/quickstart.md
CHANGED
|
@@ -11,7 +11,7 @@ npx @north-light/sdk@latest init my-app
|
|
|
11
11
|
|
|
12
12
|
This command creates a small Node server, a signing key and an env file. About ten minutes later you have an app on your laptop that signs you in with Northlight, starts an agent run on your own Northlight runtime, and texts your phone. The app runs on your machine and talks to Northlight's production directory at `https://account.northlight.ai`. There is no local Northlight stack to run, and you do not need crouter.
|
|
13
13
|
|
|
14
|
-
You need Node.js
|
|
14
|
+
You need Node.js 20.6 or later (the start command uses `--env-file`) and a phone that can receive iMessage. The server was run on Node 20.6, 20.20, 22.14, 22.22 and 26.12.
|
|
15
15
|
|
|
16
16
|
Using a coding agent? Run the same `init` command, or tell your agent: *Read https://sdk.docs.northlight.ai/SKILL.md and follow it.* See [Use your coding agent](/docs/coding-agents).
|
|
17
17
|
|
|
@@ -107,9 +107,9 @@ node --env-file=local/app.env --import tsx server.ts
|
|
|
107
107
|
|
|
108
108
|
(`npm start` runs the same command.) You should see `Listening on http://localhost:3000`.
|
|
109
109
|
|
|
110
|
-
Open `http://localhost:3000/auth/login`. Your browser goes to `account.northlight.ai`. Sign in if asked, read the consent page, and choose Allow. You land back on `http://localhost:3000/` with "Signed in" and your Northlight user id. Press **Start a run and send me a text**. The page answers "Done", shows the run's status `idle
|
|
110
|
+
Open `http://localhost:3000/auth/login`. Your browser goes to `account.northlight.ai`. Sign in if asked, read the consent page, and choose Allow. You land back on `http://localhost:3000/` with "Signed in" and your Northlight user id. Press **Start a run and send me a text**. The page answers "Done", shows the run's status `idle`, the run's reply (`pong`) and the text's `message_id`, and your phone receives "Hello from my first Northlight app." from Northlight's number.
|
|
111
111
|
|
|
112
|
-
Checked on production, as the account that owns the app: the server starts (with `npm start` too), `/` shows the sign-in link, and `/auth/login` answers `303` to `https://account.northlight.ai/authorize?client_id=…&scope=openid+profile+crtr%3Allm+crtr%3Aact+sms%3Asend…&code_challenge_method=S256…`. The consent page listed the four permissions and the monthly cap, **Allow** returned to `http://localhost:3000/` with "Signed in" and the user id, and the button page answered "Done" with status `idle` and a `message_id` for the text. In the console the key then read "Last used just now". Not yet checked on production: that the text reached the phone (the `message_id` is the provider's answer, not a delivery receipt),
|
|
112
|
+
Checked on production, as the account that owns the app: the server starts (with `npm start` too), `/` shows the sign-in link, and `/auth/login` answers `303` to `https://account.northlight.ai/authorize?client_id=…&scope=openid+profile+crtr%3Allm+crtr%3Aact+sms%3Asend…&code_challenge_method=S256…`. The consent page listed the four permissions and the monthly cap, **Allow** returned to `http://localhost:3000/` with "Signed in" and the user id, and the button page answered "Done" with status `idle` and a `message_id` for the text. In the console the key then read "Last used just now". Not yet checked on production: that the text reached the phone (the `message_id` is the provider's answer, not a delivery receipt), and the `426` case. The `pong` reply is read through `runs.reply` and has not been run on production since this example changed. Signing in as a second person needs a second account and is not covered here.
|
|
113
113
|
|
|
114
114
|
If `/` shows "One step left", `CROUTER_CLIENT_ID` is empty: repeat step 5 and restart. If a call fails with `426 runtime_version_unsupported`, your SDK is newer than the Northlight runtimes. Install the previous version with `npm i --save-exact @north-light/sdk@<version>` and tell support@northlight.ai.
|
|
115
115
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.479",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
},
|
|
138
138
|
"license": "UNLICENSED",
|
|
139
139
|
"dependencies": {
|
|
140
|
-
"@north-light/identity": "0.3.
|
|
140
|
+
"@north-light/identity": "0.3.479",
|
|
141
141
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
142
142
|
"@earendil-works/pi-ai": "1.1.0",
|
|
143
143
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.479",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.479",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@earendil-works/pi-ai": "1.1.0",
|
|
19
19
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
20
20
|
"@earendil-works/pi-tui": "1.1.0",
|
|
21
|
-
"@north-light/identity": "0.3.
|
|
21
|
+
"@north-light/identity": "0.3.479",
|
|
22
22
|
"cron-parser": "^5.6.0",
|
|
23
23
|
"esbuild": "^0.27.7",
|
|
24
24
|
"jose": "^6.2.12",
|
|
@@ -12116,17 +12116,17 @@
|
|
|
12116
12116
|
},
|
|
12117
12117
|
"packages/crouter-api": {
|
|
12118
12118
|
"name": "@north-light/api",
|
|
12119
|
-
"version": "0.3.
|
|
12119
|
+
"version": "0.3.479",
|
|
12120
12120
|
"license": "UNLICENSED"
|
|
12121
12121
|
},
|
|
12122
12122
|
"packages/crouter-env-docker": {
|
|
12123
12123
|
"name": "@north-light/env-docker",
|
|
12124
|
-
"version": "0.3.
|
|
12124
|
+
"version": "0.3.479",
|
|
12125
12125
|
"license": "UNLICENSED"
|
|
12126
12126
|
},
|
|
12127
12127
|
"packages/crouter-identity": {
|
|
12128
12128
|
"name": "@north-light/identity",
|
|
12129
|
-
"version": "0.3.
|
|
12129
|
+
"version": "0.3.479",
|
|
12130
12130
|
"license": "UNLICENSED",
|
|
12131
12131
|
"dependencies": {
|
|
12132
12132
|
"jose": "^6.2.1"
|
|
@@ -12134,25 +12134,28 @@
|
|
|
12134
12134
|
},
|
|
12135
12135
|
"packages/crouter-plugin": {
|
|
12136
12136
|
"name": "@north-light/plugin",
|
|
12137
|
-
"version": "0.3.
|
|
12137
|
+
"version": "0.3.479",
|
|
12138
12138
|
"license": "UNLICENSED",
|
|
12139
12139
|
"dependencies": {
|
|
12140
|
-
"@north-light/api": "0.3.
|
|
12141
|
-
"@north-light/identity": "0.3.
|
|
12140
|
+
"@north-light/api": "0.3.479",
|
|
12141
|
+
"@north-light/identity": "0.3.479"
|
|
12142
12142
|
}
|
|
12143
12143
|
},
|
|
12144
12144
|
"packages/crouter-sdk": {
|
|
12145
12145
|
"name": "@north-light/sdk",
|
|
12146
|
-
"version": "0.3.
|
|
12146
|
+
"version": "0.3.479",
|
|
12147
12147
|
"license": "UNLICENSED",
|
|
12148
12148
|
"dependencies": {
|
|
12149
|
-
"@north-light/api": "0.3.
|
|
12150
|
-
"@north-light/identity": "0.3.
|
|
12149
|
+
"@north-light/api": "0.3.479",
|
|
12150
|
+
"@north-light/identity": "0.3.479",
|
|
12151
12151
|
"jose": "^6.2.1"
|
|
12152
12152
|
},
|
|
12153
12153
|
"bin": {
|
|
12154
12154
|
"crouter-sdk": "dist/keygen-cli.js"
|
|
12155
12155
|
},
|
|
12156
|
+
"engines": {
|
|
12157
|
+
"node": ">=20.6.0"
|
|
12158
|
+
},
|
|
12156
12159
|
"peerDependencies": {
|
|
12157
12160
|
"pg": "^8.0.0"
|
|
12158
12161
|
},
|