skillscript-runtime 0.27.0 → 0.27.2
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/CHANGELOG.md +23 -0
- package/README.md +5 -1
- package/dist/cli.js +6 -2
- package/dist/cli.js.map +1 -1
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/help-content.js +5 -5
- package/docs/adopter-playbook.md +4 -6
- package/docs/configuration.md +1 -0
- package/docs/language-reference.md +127 -156
- package/examples/connectors/DataStoreTemplate/DataStoreTemplate.ts +14 -0
- package/examples/onboarding-scaffold/file-data-store.ts +13 -2
- package/examples/onboarding-scaffold/openai-local-model.ts +3 -1
- package/examples/onboarding-scaffold/tmux-shell-agent-connector.ts +41 -5
- package/examples/skillscripts/classify-support-ticket.skill.provenance.json +10 -0
- package/examples/skillscripts/data-store-roundtrip.skill.provenance.json +10 -0
- package/examples/skillscripts/doc-qa-with-citations.skill.provenance.json +10 -0
- package/examples/skillscripts/feedback-sentiment-scan.skill.provenance.json +10 -0
- package/examples/skillscripts/hello-world.skill.provenance.json +1 -1
- package/examples/skillscripts/morning-brief.skill.md +5 -6
- package/examples/skillscripts/morning-brief.skill.provenance.json +10 -0
- package/examples/skillscripts/queue-length-monitor.skill.provenance.json +10 -0
- package/examples/skillscripts/service-health-watch.skill.provenance.json +10 -0
- package/examples/skillscripts/skill-store-roundtrip.skill.provenance.json +10 -0
- package/examples/skillscripts/youtrack-morning-sweep.skill.provenance.json +10 -0
- package/package.json +1 -1
|
@@ -165,4 +165,18 @@ export class DataStoreTemplate implements DataStore {
|
|
|
165
165
|
// - Return { id, created_at }
|
|
166
166
|
throw new Error("TODO: write() — persist record; return { id, created_at }.");
|
|
167
167
|
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Direct lookup by substrate-assigned id (v0.13.8 — lets `data_read`
|
|
171
|
+
* inspect a record without a query roundtrip). Return `null` when the id
|
|
172
|
+
* isn't found — do NOT throw; null-on-miss is the DataStore convention
|
|
173
|
+
* (contrast SkillStore, which throws `SkillNotFoundError`). Substrates
|
|
174
|
+
* without a native by-id lookup can implement via a filtered query, but
|
|
175
|
+
* the null semantics must hold.
|
|
176
|
+
*/
|
|
177
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
178
|
+
async get(_id: string): Promise<PortableData | null> {
|
|
179
|
+
// TODO — fetch one record by id from your substrate; null when missing.
|
|
180
|
+
throw new Error("TODO: get() — return the record for this id, or null.");
|
|
181
|
+
}
|
|
168
182
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// their concrete substrate (e.g., swap the JSON file for a Postgres
|
|
6
6
|
// table, the substring match for actual full-text search, etc.).
|
|
7
7
|
//
|
|
8
|
-
// **Scope.** Implements `query()` + `write()` per the DataStore contract.
|
|
8
|
+
// **Scope.** Implements `query()` + `write()` + `get()` per the DataStore contract.
|
|
9
9
|
|
|
10
10
|
import { readFileSync, existsSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
@@ -35,7 +35,9 @@ export class FileDataStore implements DataStore {
|
|
|
35
35
|
implementation: "FileDataStore",
|
|
36
36
|
contract_version: "1.0.0",
|
|
37
37
|
features: {
|
|
38
|
-
|
|
38
|
+
// FTS is the baseline query mode — declared via `manifest().supported_modes`,
|
|
39
|
+
// not a feature flag. Flags are the closed `DataStoreFeature` set.
|
|
40
|
+
supports_writes: true,
|
|
39
41
|
supports_semantic: false,
|
|
40
42
|
supports_rerank: false,
|
|
41
43
|
},
|
|
@@ -96,11 +98,20 @@ export class FileDataStore implements DataStore {
|
|
|
96
98
|
return { id, created_at };
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Direct lookup by id (v0.13.8 DataStore contract). Null-on-miss —
|
|
103
|
+
* never throws for an unknown id.
|
|
104
|
+
*/
|
|
105
|
+
async get(id: string): Promise<PortableData | null> {
|
|
106
|
+
return this.loadFile().find((r) => r.id === id) ?? null;
|
|
107
|
+
}
|
|
108
|
+
|
|
99
109
|
async manifest(): Promise<ManifestInfo> {
|
|
100
110
|
return {
|
|
101
111
|
capabilities_version: "1",
|
|
102
112
|
manifest: {
|
|
103
113
|
kind: "file-data-store",
|
|
114
|
+
supported_modes: ["fts"],
|
|
104
115
|
file_path: this.config.filePath,
|
|
105
116
|
record_count: this.loadFile().length,
|
|
106
117
|
supports_write: true,
|
|
@@ -43,8 +43,10 @@ export class OpenAILocalModel implements LocalModel {
|
|
|
43
43
|
implementation: "OpenAILocalModel",
|
|
44
44
|
contract_version: "1.0.0",
|
|
45
45
|
features: {
|
|
46
|
+
supports_max_tokens: true,
|
|
47
|
+
supports_timeout: false,
|
|
46
48
|
supports_streaming: false,
|
|
47
|
-
|
|
49
|
+
supports_embedding: false,
|
|
48
50
|
},
|
|
49
51
|
};
|
|
50
52
|
}
|
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
// with agents running in tmux sessions can wire `# Output: agent: <agent>`
|
|
6
6
|
// end-to-end against this impl.
|
|
7
7
|
//
|
|
8
|
-
// **Scope.** Implements
|
|
9
|
-
// `
|
|
10
|
-
//
|
|
8
|
+
// **Scope.** Implements the full AgentConnector contract: `deliver()` +
|
|
9
|
+
// `list_agents()` + `wake()` + `agent_status()` + `health_check()` +
|
|
10
|
+
// `request_response()` + `manifest()`. `wake()` degrades to a no-op (tmux
|
|
11
|
+
// panes are always live; wake is for harnesses with sleep modes) and
|
|
12
|
+
// `request_response()` throws not-implemented (send-keys is fire-and-forget).
|
|
11
13
|
|
|
12
14
|
import { spawn } from "node:child_process";
|
|
13
15
|
import type {
|
|
@@ -16,6 +18,8 @@ import type {
|
|
|
16
18
|
AgentStatus,
|
|
17
19
|
DeliveryPayload,
|
|
18
20
|
DeliveryReceipt,
|
|
21
|
+
RequestResponseOpts,
|
|
22
|
+
Response,
|
|
19
23
|
WakeOpts,
|
|
20
24
|
WakeReceipt,
|
|
21
25
|
} from "skillscript-runtime/connectors";
|
|
@@ -36,7 +40,10 @@ export class TmuxShellAgentConnector implements AgentConnector {
|
|
|
36
40
|
connector_type: "agent_connector",
|
|
37
41
|
implementation: "TmuxShellAgentConnector",
|
|
38
42
|
contract_version: "1.0.0",
|
|
39
|
-
|
|
43
|
+
// AgentConnector flags are method-presence shape (one per contract
|
|
44
|
+
// method). `wake` is present but degrades to a no-op — see wake()'s
|
|
45
|
+
// `woken: false` receipt.
|
|
46
|
+
features: { deliver: true, wake: true, list_agents: true, agent_status: true },
|
|
40
47
|
};
|
|
41
48
|
}
|
|
42
49
|
|
|
@@ -75,10 +82,13 @@ export class TmuxShellAgentConnector implements AgentConnector {
|
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
async wake(agent_id: string, _opts?: WakeOpts): Promise<WakeReceipt> {
|
|
78
|
-
// tmux panes are always live
|
|
85
|
+
// tmux panes are always live — there is nothing to wake. `woken: false`
|
|
86
|
+
// is the honest receipt: the substrate performed no wake action (the
|
|
87
|
+
// contract reads false as "degraded to deliver-only").
|
|
79
88
|
const session = this.config.sessionMap[agent_id];
|
|
80
89
|
return {
|
|
81
90
|
woken_at: Date.now(),
|
|
91
|
+
woken: false,
|
|
82
92
|
...(session !== undefined ? { session_id: session } : {}),
|
|
83
93
|
};
|
|
84
94
|
}
|
|
@@ -87,6 +97,32 @@ export class TmuxShellAgentConnector implements AgentConnector {
|
|
|
87
97
|
return this.config.sessionMap[agent_id] !== undefined ? "active" : "unknown";
|
|
88
98
|
}
|
|
89
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Substrate liveness: is the `tmux` binary reachable? Invoked at
|
|
102
|
+
* `Registry.registerAgentConnector()` — a false return refuses the wiring
|
|
103
|
+
* early instead of failing on the first deliver.
|
|
104
|
+
*/
|
|
105
|
+
async health_check(): Promise<boolean> {
|
|
106
|
+
try {
|
|
107
|
+
await this.tmux(["-V"]);
|
|
108
|
+
return true;
|
|
109
|
+
} catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* tmux send-keys is fire-and-forget — there is no reply channel to
|
|
116
|
+
* correlate a response on. Throw not-implemented per the contract's
|
|
117
|
+
* documented pattern (see NoOpAgentConnector) rather than fake a reply.
|
|
118
|
+
*/
|
|
119
|
+
async request_response(agent_id: string, _payload: DeliveryPayload, _opts: RequestResponseOpts): Promise<Response> {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`TmuxShellAgentConnector: request_response(${agent_id}) not implemented — ` +
|
|
122
|
+
`tmux send-keys has no reply channel. Use deliver() for one-way output.`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
90
126
|
async manifest(): Promise<ManifestInfo> {
|
|
91
127
|
return {
|
|
92
128
|
capabilities_version: "1",
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
# Skill: morning-brief
|
|
2
2
|
# Status: Draft
|
|
3
|
-
# Description: Compose a daily morning brief from calendar, mailbox, and overnight notes when the cron trigger fires at 7am. Delivers via the agent: lifecycle hook to the receiving agent, who decides whether to surface to Slack / Discord / etc. Requires a `calendar` connector configured in connectors.json (the dotted `$ calendar.*` form). `model=qwen` is a representative LocalModel alias — adopters register one under whatever name fits (the bundled bootstrap registers `default`).
|
|
3
|
+
# Description: Compose a daily morning brief from calendar, mailbox, and overnight notes when the cron trigger fires at 7am. Delivers via the agent: lifecycle hook to the receiving agent, who decides whether to surface to Slack / Discord / etc. Requires a `calendar` connector configured in connectors.json (the dotted `$ calendar.*` form). `model=qwen` is a representative LocalModel alias — adopters register one under whatever name fits (the bundled bootstrap registers `default`). Every leg carries a per-leg `(fallback:)` so one failed source degrades loudly instead of sinking the whole gather; BRIEF itself is fallback-bound so the output template always renders.
|
|
4
4
|
# Vars: AGENT, BRIEF_HORIZON_HOURS=24
|
|
5
5
|
# Triggers: cron: 0 7 * * *
|
|
6
|
-
# OnError: morning-brief-degraded
|
|
7
6
|
# Output: agent: ${AGENT}
|
|
8
7
|
|
|
9
8
|
${BRIEF}
|
|
10
9
|
|
|
11
10
|
calendar:
|
|
12
|
-
$ calendar.list_events horizon_hours=${BRIEF_HORIZON_HOURS} -> EVENTS
|
|
11
|
+
$ calendar.list_events horizon_hours=${BRIEF_HORIZON_HOURS} -> EVENTS (fallback: "(calendar unavailable)")
|
|
13
12
|
|
|
14
13
|
mailbox:
|
|
15
|
-
$ data_read mode=fts query="messages for ${AGENT}" limit=10 -> MAIL
|
|
14
|
+
$ data_read mode=fts query="messages for ${AGENT}" limit=10 -> MAIL (fallback: "(mailbox unavailable)")
|
|
16
15
|
|
|
17
16
|
overnight:
|
|
18
|
-
$ data_read mode=rerank query="overnight notes and writes" limit=15 -> NOTES
|
|
17
|
+
$ data_read mode=rerank query="overnight notes and writes" limit=15 -> NOTES (fallback: "(overnight notes unavailable)")
|
|
19
18
|
|
|
20
19
|
compose: needs: calendar, mailbox, overnight
|
|
21
|
-
$ llm prompt="Compose a concise morning brief. Calendar: ${EVENTS|json}. Mailbox: ${MAIL|json}. Overnight notes: ${NOTES|json}. Three sections, six bullets max each." model=qwen maxTokens=1200 -> BRIEF
|
|
20
|
+
$ llm prompt="Compose a concise morning brief. Calendar: ${EVENTS|json}. Mailbox: ${MAIL|json}. Overnight notes: ${NOTES|json}. Three sections, six bullets max each. A source marked unavailable should be reported as such, not invented." model=qwen maxTokens=1200 -> BRIEF (fallback: "(morning brief unavailable — compose failed; check the llm connector)")
|
|
22
21
|
|
|
23
22
|
default: compose
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillscript-runtime",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.2",
|
|
4
4
|
"description": "Runtime, compiler, lint, CLI, and dashboard for Skillscript — a small declarative language for authoring agent workflows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Scott Shwarts <scotts@pobox.com>",
|