-
Notifications
You must be signed in to change notification settings - Fork 256
Expand file tree
/
Copy pathdescription.ts
More file actions
72 lines (65 loc) · 3.89 KB
/
Copy pathdescription.ts
File metadata and controls
72 lines (65 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { Effect } from "effect";
import type { Executor, Source } from "@executor-js/sdk/core";
/**
* Builds a tool description dynamically.
*
* Structure:
* 1. Workflow (top — critical, least likely to be truncated)
* 2. Available namespaces (bottom)
*/
export const buildExecuteDescription = (executor: Executor): Effect.Effect<string> =>
Effect.gen(function* () {
const sources: readonly Source[] = yield* executor.sources
.list()
.pipe(Effect.orDie, Effect.withSpan("executor.sources.list"));
const description = yield* Effect.sync(() => formatDescription(sources)).pipe(
Effect.withSpan("schema.compile.description", {
attributes: { "executor.source_count": sources.length },
}),
);
yield* Effect.annotateCurrentSpan({
"executor.source_count": sources.length,
"schema.kind": "execute",
});
return description;
}).pipe(Effect.withSpan("schema.describe.execute"));
const formatDescription = (sources: readonly Source[]): string => {
const lines: string[] = [
"Execute TypeScript in a sandboxed runtime with access to configured API tools.",
"",
"## Workflow",
"",
'1. `const { items: matches } = await tools.search({ query: "<intent + key nouns>", limit: 12 });`',
'2. `const path = matches[0]?.path; if (!path) return "No matching tools found.";`',
"3. `const details = await tools.describe.tool({ path });`",
"4. Use `details.inputTypeScript` / `details.outputTypeScript` and `details.typeScriptDefinitions` for compact shapes.",
"5. Use `tools.executor.sources.list()` when you need configured source inventory.",
"6. Call the tool: `const result = await tools.<path>(input);`",
"",
"## Rules",
"",
"- `tools.search()` returns paginated, ranked matches: `{ items, total, hasMore, nextOffset }`. Best-first. Use short intent phrases like `github issues`, `repo details`, or `create calendar event`.",
'- When you already know the namespace, narrow with `tools.search({ namespace: "github", query: "issues" })`.',
"- `tools.executor.sources.list()` returns the same paged shape: `{ items: [{ id, toolCount, ... }], total, hasMore, nextOffset }`.",
"- If `hasMore` is true and you didn't find what you need, fetch the next page: `tools.search({ query, offset: nextOffset, limit })`. Same `offset` parameter on `tools.executor.sources.list({ offset, limit })`.",
"- Always use the namespace prefix when calling tools: `tools.<namespace>.<tool>(args)`. Example: `tools.home_assistant_rest_api.states.getState(...)` — not `tools.states.getState(...)`.",
"- The `tools` object is a lazy proxy — `Object.keys(tools)` won't work. Use `tools.search()` or `tools.executor.sources.list()` instead.",
'- Pass an object to system tools, e.g. `tools.search({ query: "..." })`, `tools.executor.sources.list()`, and `tools.describe.tool({ path })`.',
"- `tools.describe.tool()` returns compact TypeScript shapes. Use `inputTypeScript`, `outputTypeScript`, and `typeScriptDefinitions`.",
"- For tools that return large collections (e.g. `getStates`, `getAll`), filter results in code rather than calling per-item tools.",
"- Do not use `fetch` — all API calls go through `tools.*`.",
"- If execution pauses for interaction, resume it with the returned `resumePayload`.",
"- TypeScript type syntax (`: T`, `as T`, generics, interfaces, type aliases) is stripped before execution — feel free to write idiomatic TypeScript using the shapes from `tools.describe.tool()`. Decorators and `enum` are not supported.",
];
if (sources.length > 0) {
lines.push("");
lines.push("## Available namespaces");
lines.push("");
const sorted = [...sources].sort((a, b) => a.id.localeCompare(b.id));
for (const source of sorted) {
const label = source.name;
lines.push(`- \`${source.id}\`${label !== source.id ? ` — ${label}` : ""}`);
}
}
return lines.join("\n");
};