@amodalai/runtime 0.3.49 → 0.3.51
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/src/agent/completion-tools.integration.test.d.ts +6 -0
- package/dist/src/agent/completion-tools.integration.test.js +263 -0
- package/dist/src/agent/completion-tools.integration.test.js.map +1 -0
- package/dist/src/agent/load-template-plan.integration.test.d.ts +6 -0
- package/dist/src/agent/load-template-plan.integration.test.js +152 -0
- package/dist/src/agent/load-template-plan.integration.test.js.map +1 -0
- package/dist/src/agent/local-server.js +64 -9
- package/dist/src/agent/local-server.js.map +1 -1
- package/dist/src/agent/loop-types.d.ts +12 -2
- package/dist/src/agent/loop.test.js +5 -2
- package/dist/src/agent/loop.test.js.map +1 -1
- package/dist/src/agent/propose-plan.integration.test.d.ts +6 -0
- package/dist/src/agent/propose-plan.integration.test.js +186 -0
- package/dist/src/agent/propose-plan.integration.test.js.map +1 -0
- package/dist/src/agent/routes/package-updates.d.ts +42 -0
- package/dist/src/agent/routes/package-updates.js +207 -0
- package/dist/src/agent/routes/package-updates.js.map +1 -0
- package/dist/src/agent/routes/package-updates.test.d.ts +6 -0
- package/dist/src/agent/routes/package-updates.test.js +25 -0
- package/dist/src/agent/routes/package-updates.test.js.map +1 -0
- package/dist/src/agent/setup-state.integration.test.d.ts +6 -0
- package/dist/src/agent/setup-state.integration.test.js +182 -0
- package/dist/src/agent/setup-state.integration.test.js.map +1 -0
- package/dist/src/agent/snapshot-server.js +1 -0
- package/dist/src/agent/snapshot-server.js.map +1 -1
- package/dist/src/agent/states/executing.d.ts +6 -0
- package/dist/src/agent/states/executing.js +63 -27
- package/dist/src/agent/states/executing.js.map +1 -1
- package/dist/src/agent/states/streaming.js +18 -2
- package/dist/src/agent/states/streaming.js.map +1 -1
- package/dist/src/agent/tool-executor-local.js +11 -2
- package/dist/src/agent/tool-executor-local.js.map +1 -1
- package/dist/src/agent/validate-connection.integration.test.d.ts +6 -0
- package/dist/src/agent/validate-connection.integration.test.js +160 -0
- package/dist/src/agent/validate-connection.integration.test.js.map +1 -0
- package/dist/src/api/create-agent.js +1 -0
- package/dist/src/api/create-agent.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/intent/executor.d.ts +48 -0
- package/dist/src/intent/executor.js +420 -0
- package/dist/src/intent/executor.js.map +1 -0
- package/dist/src/intent/executor.test.d.ts +6 -0
- package/dist/src/intent/executor.test.js +543 -0
- package/dist/src/intent/executor.test.js.map +1 -0
- package/dist/src/intent/index.d.ts +10 -0
- package/dist/src/intent/index.js +9 -0
- package/dist/src/intent/index.js.map +1 -0
- package/dist/src/intent/loader.d.ts +16 -0
- package/dist/src/intent/loader.js +112 -0
- package/dist/src/intent/loader.js.map +1 -0
- package/dist/src/intent/loader.test.d.ts +6 -0
- package/dist/src/intent/loader.test.js +86 -0
- package/dist/src/intent/loader.test.js.map +1 -0
- package/dist/src/intent/matcher.d.ts +26 -0
- package/dist/src/intent/matcher.js +29 -0
- package/dist/src/intent/matcher.js.map +1 -0
- package/dist/src/intent/matcher.test.d.ts +6 -0
- package/dist/src/intent/matcher.test.js +53 -0
- package/dist/src/intent/matcher.test.js.map +1 -0
- package/dist/src/intent/onboarding.e2e.test.d.ts +6 -0
- package/dist/src/intent/onboarding.e2e.test.js +394 -0
- package/dist/src/intent/onboarding.e2e.test.js.map +1 -0
- package/dist/src/routes/ai-stream.js +96 -3
- package/dist/src/routes/ai-stream.js.map +1 -1
- package/dist/src/routes/session-resolver.js +16 -0
- package/dist/src/routes/session-resolver.js.map +1 -1
- package/dist/src/session/credential-scrubber.d.ts +35 -0
- package/dist/src/session/credential-scrubber.js +150 -0
- package/dist/src/session/credential-scrubber.js.map +1 -0
- package/dist/src/session/credential-scrubber.test.d.ts +6 -0
- package/dist/src/session/credential-scrubber.test.js +192 -0
- package/dist/src/session/credential-scrubber.test.js.map +1 -0
- package/dist/src/session/manager.intent.test.d.ts +6 -0
- package/dist/src/session/manager.intent.test.js +197 -0
- package/dist/src/session/manager.intent.test.js.map +1 -0
- package/dist/src/session/manager.js +114 -0
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/session-builder.d.ts +16 -1
- package/dist/src/session/session-builder.js +209 -41
- package/dist/src/session/session-builder.js.map +1 -1
- package/dist/src/session/store.js +48 -2
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/tool-context-factory.js +12 -0
- package/dist/src/session/tool-context-factory.js.map +1 -1
- package/dist/src/session/types.d.ts +12 -1
- package/dist/src/setup/commit-setup.d.ts +94 -0
- package/dist/src/setup/commit-setup.js +154 -0
- package/dist/src/setup/commit-setup.js.map +1 -0
- package/dist/src/setup/commit-setup.test.d.ts +6 -0
- package/dist/src/setup/commit-setup.test.js +310 -0
- package/dist/src/setup/commit-setup.test.js.map +1 -0
- package/dist/src/tools/README.md +270 -0
- package/dist/src/tools/admin-tools.d.ts +27 -0
- package/dist/src/tools/admin-tools.js +734 -0
- package/dist/src/tools/admin-tools.js.map +1 -0
- package/dist/src/tools/agent-package-discovery.test.d.ts +6 -0
- package/dist/src/tools/agent-package-discovery.test.js +90 -0
- package/dist/src/tools/agent-package-discovery.test.js.map +1 -0
- package/dist/src/tools/builtin/ask-choice.d.ts +8 -0
- package/dist/src/tools/builtin/ask-choice.js +54 -0
- package/dist/src/tools/builtin/ask-choice.js.map +1 -0
- package/dist/src/tools/context.d.ts +154 -0
- package/dist/src/tools/context.js +30 -0
- package/dist/src/tools/context.js.map +1 -0
- package/dist/src/tools/custom-tool-adapter.d.ts +33 -2
- package/dist/src/tools/custom-tool-adapter.js +38 -1
- package/dist/src/tools/custom-tool-adapter.js.map +1 -1
- package/dist/src/tools/custom-tool-adapter.test.js +48 -0
- package/dist/src/tools/custom-tool-adapter.test.js.map +1 -1
- package/dist/src/tools/fetch-url-tool.js +2 -0
- package/dist/src/tools/fetch-url-tool.js.map +1 -1
- package/dist/src/tools/file-tools.js +16 -0
- package/dist/src/tools/file-tools.js.map +1 -1
- package/dist/src/tools/fs/local.test.d.ts +6 -0
- package/dist/src/tools/fs/local.test.js +126 -0
- package/dist/src/tools/fs/local.test.js.map +1 -0
- package/dist/src/tools/index.d.ts +35 -0
- package/dist/src/tools/index.js +11 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/mcp-tool-adapter.js +2 -0
- package/dist/src/tools/mcp-tool-adapter.js.map +1 -1
- package/dist/src/tools/memory-tool.js +23 -1
- package/dist/src/tools/memory-tool.js.map +1 -1
- package/dist/src/tools/permissions.d.ts +36 -0
- package/dist/src/tools/permissions.js +97 -0
- package/dist/src/tools/permissions.js.map +1 -0
- package/dist/src/tools/permissions.test.d.ts +6 -0
- package/dist/src/tools/permissions.test.js +62 -0
- package/dist/src/tools/permissions.test.js.map +1 -0
- package/dist/src/tools/request-tool.js +2 -0
- package/dist/src/tools/request-tool.js.map +1 -1
- package/dist/src/tools/sdk-context.d.ts +43 -0
- package/dist/src/tools/sdk-context.js +94 -0
- package/dist/src/tools/sdk-context.js.map +1 -0
- package/dist/src/tools/sdk-context.test.d.ts +6 -0
- package/dist/src/tools/sdk-context.test.js +134 -0
- package/dist/src/tools/sdk-context.test.js.map +1 -0
- package/dist/src/tools/store-tools.js +6 -0
- package/dist/src/tools/store-tools.js.map +1 -1
- package/dist/src/tools/types.d.ts +53 -14
- package/dist/src/tools/web-search-tool.js +2 -0
- package/dist/src/tools/web-search-tool.js.map +1 -1
- package/dist/src/types.d.ts +164 -28
- package/dist/src/types.js +9 -3
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -4
- package/dist/src/tools/agent-config-tool.d.ts +0 -7
- package/dist/src/tools/agent-config-tool.js +0 -78
- package/dist/src/tools/agent-config-tool.js.map +0 -1
- package/dist/src/tools/collect-secret-tool.d.ts +0 -7
- package/dist/src/tools/collect-secret-tool.js +0 -47
- package/dist/src/tools/collect-secret-tool.js.map +0 -1
- package/dist/src/tools/fs/http.d.ts +0 -37
- package/dist/src/tools/fs/http.js +0 -88
- package/dist/src/tools/fs/http.js.map +0 -1
- package/dist/src/tools/http-file-tools.d.ts +0 -13
- package/dist/src/tools/http-file-tools.js +0 -146
- package/dist/src/tools/http-file-tools.js.map +0 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Load intents from `<repoPath>/intents/<id>/intent.ts`. Each subdir is
|
|
8
|
+
* one intent; its `intent.ts` default-exports an `IntentDefinition`.
|
|
9
|
+
*
|
|
10
|
+
* Compiles each entry with esbuild (same approach as `tool-executor-local`
|
|
11
|
+
* uses for tool handlers) so authors can split helpers across sibling
|
|
12
|
+
* `.ts` files inside the intent's directory. Output goes into a
|
|
13
|
+
* sibling `.build/` directory so the source tree stays clean.
|
|
14
|
+
*
|
|
15
|
+
* Skipped silently when:
|
|
16
|
+
* - `<repoPath>/intents/` doesn't exist (most agents don't have intents)
|
|
17
|
+
* - A subdir has no `intent.ts` (probably a future siblings dir)
|
|
18
|
+
*
|
|
19
|
+
* Throws when:
|
|
20
|
+
* - `intent.ts` exists but the default export isn't a valid
|
|
21
|
+
* IntentDefinition shape (caller surface, fail fast)
|
|
22
|
+
*/
|
|
23
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
24
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
25
|
+
import * as path from 'node:path';
|
|
26
|
+
import { pathToFileURL } from 'node:url';
|
|
27
|
+
/**
|
|
28
|
+
* Read the intents directory and return a sorted list of loaded
|
|
29
|
+
* IntentDefinitions. Empty array when the directory is missing.
|
|
30
|
+
*
|
|
31
|
+
* Sort order is alphabetical by directory name. `matchIntent` walks
|
|
32
|
+
* the list in registration order, so the directory name controls
|
|
33
|
+
* which regex is tested first when two intents could match the same
|
|
34
|
+
* input. Author intent ids accordingly (the id IS the directory name).
|
|
35
|
+
*/
|
|
36
|
+
export async function loadIntents(repoPath) {
|
|
37
|
+
const intentsDir = path.join(repoPath, 'intents');
|
|
38
|
+
if (!existsSync(intentsDir))
|
|
39
|
+
return [];
|
|
40
|
+
let dirEntries;
|
|
41
|
+
try {
|
|
42
|
+
dirEntries = await readdir(intentsDir);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
dirEntries.sort();
|
|
48
|
+
const loaded = [];
|
|
49
|
+
for (const name of dirEntries) {
|
|
50
|
+
if (name.startsWith('.') || name.startsWith('_'))
|
|
51
|
+
continue;
|
|
52
|
+
const subdirPath = path.join(intentsDir, name);
|
|
53
|
+
let stats;
|
|
54
|
+
try {
|
|
55
|
+
stats = await stat(subdirPath);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (!stats.isDirectory())
|
|
61
|
+
continue;
|
|
62
|
+
const intentFile = path.join(subdirPath, 'intent.ts');
|
|
63
|
+
if (!existsSync(intentFile))
|
|
64
|
+
continue;
|
|
65
|
+
const def = await loadIntentModule(name, intentFile);
|
|
66
|
+
loaded.push(def);
|
|
67
|
+
}
|
|
68
|
+
return loaded;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Compile + import a single intent.ts. esbuild runs with
|
|
72
|
+
* `bundle: true, packages: 'external'` so sibling .ts helpers get
|
|
73
|
+
* inlined while npm + node:* imports stay external for normal
|
|
74
|
+
* Node resolution.
|
|
75
|
+
*/
|
|
76
|
+
async function loadIntentModule(dirName, intentFilePath) {
|
|
77
|
+
const buildDir = path.join(path.dirname(intentFilePath), '.build');
|
|
78
|
+
const outFile = path.join(buildDir, 'intent.mjs');
|
|
79
|
+
mkdirSync(buildDir, { recursive: true });
|
|
80
|
+
const { build } = await import('esbuild');
|
|
81
|
+
await build({
|
|
82
|
+
entryPoints: [intentFilePath],
|
|
83
|
+
outfile: outFile,
|
|
84
|
+
bundle: true,
|
|
85
|
+
packages: 'external',
|
|
86
|
+
format: 'esm',
|
|
87
|
+
platform: 'node',
|
|
88
|
+
target: 'node20',
|
|
89
|
+
logLevel: 'warning',
|
|
90
|
+
});
|
|
91
|
+
const moduleUrl = pathToFileURL(outFile).href;
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- dynamic import boundary; validated below
|
|
93
|
+
const mod = (await import(moduleUrl));
|
|
94
|
+
const def = mod.default;
|
|
95
|
+
if (!isValidIntentDefinition(def)) {
|
|
96
|
+
throw new Error(`Intent "${dirName}" at ${intentFilePath} must default-export an IntentDefinition with {id: string, regex: RegExp, handle: function}.`);
|
|
97
|
+
}
|
|
98
|
+
if (def.id !== dirName) {
|
|
99
|
+
throw new Error(`Intent at ${intentFilePath} has id "${def.id}" but lives in directory "${dirName}". The id must match the directory name.`);
|
|
100
|
+
}
|
|
101
|
+
return def;
|
|
102
|
+
}
|
|
103
|
+
function isValidIntentDefinition(value) {
|
|
104
|
+
if (typeof value !== 'object' || value === null)
|
|
105
|
+
return false;
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- discriminating shape check
|
|
107
|
+
const v = value;
|
|
108
|
+
return (typeof v['id'] === 'string' &&
|
|
109
|
+
v['regex'] instanceof RegExp &&
|
|
110
|
+
typeof v['handle'] === 'function');
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/intent/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import { loadIntents } from './loader.js';
|
|
11
|
+
describe('loadIntents', () => {
|
|
12
|
+
let repoPath;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
repoPath = await mkdtemp(path.join(tmpdir(), 'intent-loader-test-'));
|
|
15
|
+
});
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
await rm(repoPath, { recursive: true, force: true });
|
|
18
|
+
});
|
|
19
|
+
it('returns empty array when intents/ does not exist', async () => {
|
|
20
|
+
const intents = await loadIntents(repoPath);
|
|
21
|
+
expect(intents).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
it('loads a single valid intent', async () => {
|
|
24
|
+
const intentDir = path.join(repoPath, 'intents', 'echo');
|
|
25
|
+
await mkdir(intentDir, { recursive: true });
|
|
26
|
+
await writeFile(path.join(intentDir, 'intent.ts'), `export default {
|
|
27
|
+
id: 'echo',
|
|
28
|
+
regex: /^echo (.+)$/,
|
|
29
|
+
async handle(ctx) { return {}; },
|
|
30
|
+
};`);
|
|
31
|
+
const intents = await loadIntents(repoPath);
|
|
32
|
+
expect(intents).toHaveLength(1);
|
|
33
|
+
expect(intents[0].id).toBe('echo');
|
|
34
|
+
expect(intents[0].regex.source).toBe('^echo (.+)$');
|
|
35
|
+
});
|
|
36
|
+
it('loads multiple intents alphabetically sorted', async () => {
|
|
37
|
+
for (const id of ['banana', 'apple', 'cherry']) {
|
|
38
|
+
const intentDir = path.join(repoPath, 'intents', id);
|
|
39
|
+
await mkdir(intentDir, { recursive: true });
|
|
40
|
+
await writeFile(path.join(intentDir, 'intent.ts'), `export default { id: '${id}', regex: /^${id}$/, async handle() { return {}; } };`);
|
|
41
|
+
}
|
|
42
|
+
const intents = await loadIntents(repoPath);
|
|
43
|
+
expect(intents.map((i) => i.id)).toEqual(['apple', 'banana', 'cherry']);
|
|
44
|
+
});
|
|
45
|
+
it('skips subdirs without intent.ts', async () => {
|
|
46
|
+
await mkdir(path.join(repoPath, 'intents', 'just-a-folder'), { recursive: true });
|
|
47
|
+
const intents = await loadIntents(repoPath);
|
|
48
|
+
expect(intents).toEqual([]);
|
|
49
|
+
});
|
|
50
|
+
it('skips dot- and underscore-prefixed entries', async () => {
|
|
51
|
+
for (const name of ['.hidden', '_private', '.build']) {
|
|
52
|
+
const dir = path.join(repoPath, 'intents', name);
|
|
53
|
+
await mkdir(dir, { recursive: true });
|
|
54
|
+
await writeFile(path.join(dir, 'intent.ts'), `export default { id: 'shouldnotload', regex: /^x$/, async handle() { return {}; } };`);
|
|
55
|
+
}
|
|
56
|
+
const intents = await loadIntents(repoPath);
|
|
57
|
+
expect(intents).toEqual([]);
|
|
58
|
+
});
|
|
59
|
+
it('rejects malformed default export', async () => {
|
|
60
|
+
const intentDir = path.join(repoPath, 'intents', 'bad');
|
|
61
|
+
await mkdir(intentDir, { recursive: true });
|
|
62
|
+
await writeFile(path.join(intentDir, 'intent.ts'), `export default { id: 'bad', regex: 'not-a-regex', handle: 42 };`);
|
|
63
|
+
await expect(loadIntents(repoPath)).rejects.toThrow(/IntentDefinition/);
|
|
64
|
+
});
|
|
65
|
+
it('rejects id mismatch with directory name', async () => {
|
|
66
|
+
const intentDir = path.join(repoPath, 'intents', 'directory-name');
|
|
67
|
+
await mkdir(intentDir, { recursive: true });
|
|
68
|
+
await writeFile(path.join(intentDir, 'intent.ts'), `export default { id: 'different-id', regex: /^x$/, async handle() { return {}; } };`);
|
|
69
|
+
await expect(loadIntents(repoPath)).rejects.toThrow(/must match the directory name/);
|
|
70
|
+
});
|
|
71
|
+
it('inlines sibling .ts helpers via esbuild bundle', async () => {
|
|
72
|
+
const intentDir = path.join(repoPath, 'intents', 'with-helper');
|
|
73
|
+
await mkdir(intentDir, { recursive: true });
|
|
74
|
+
await writeFile(path.join(intentDir, 'helper.ts'), `export const greeting = 'hi';`);
|
|
75
|
+
await writeFile(path.join(intentDir, 'intent.ts'), `import {greeting} from './helper.js';
|
|
76
|
+
export default {
|
|
77
|
+
id: 'with-helper',
|
|
78
|
+
regex: new RegExp('^' + greeting + '$'),
|
|
79
|
+
async handle() { return {}; },
|
|
80
|
+
};`);
|
|
81
|
+
const intents = await loadIntents(repoPath);
|
|
82
|
+
expect(intents).toHaveLength(1);
|
|
83
|
+
expect(intents[0].regex.test('hi')).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.js","sourceRoot":"","sources":["../../../src/intent/loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import type { IntentDefinition } from '@amodalai/types';
|
|
7
|
+
/**
|
|
8
|
+
* Result of a successful intent match. The runtime hands this to the
|
|
9
|
+
* bypass executor (`runIntent`) which builds the IntentContext, calls
|
|
10
|
+
* the handler, and emits the SSE event sequence.
|
|
11
|
+
*/
|
|
12
|
+
export interface IntentMatch {
|
|
13
|
+
intent: IntentDefinition;
|
|
14
|
+
match: RegExpExecArray;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Walk the intent list in registration order and return the first
|
|
18
|
+
* regex match against `input`. Returns null when nothing matches —
|
|
19
|
+
* the caller falls through to the agent loop.
|
|
20
|
+
*
|
|
21
|
+
* "First match wins" is intentional: there's no priority field and no
|
|
22
|
+
* tie-breaking. If two intents would match the same input, the one
|
|
23
|
+
* loaded earlier wins. Intent authors keep regexes precise + anchored
|
|
24
|
+
* (`^...$`) to avoid surprises.
|
|
25
|
+
*/
|
|
26
|
+
export declare function matchIntent(intents: readonly IntentDefinition[], input: string): IntentMatch | null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Walk the intent list in registration order and return the first
|
|
8
|
+
* regex match against `input`. Returns null when nothing matches —
|
|
9
|
+
* the caller falls through to the agent loop.
|
|
10
|
+
*
|
|
11
|
+
* "First match wins" is intentional: there's no priority field and no
|
|
12
|
+
* tie-breaking. If two intents would match the same input, the one
|
|
13
|
+
* loaded earlier wins. Intent authors keep regexes precise + anchored
|
|
14
|
+
* (`^...$`) to avoid surprises.
|
|
15
|
+
*/
|
|
16
|
+
export function matchIntent(intents, input) {
|
|
17
|
+
for (const intent of intents) {
|
|
18
|
+
// Reset lastIndex defensively in case the regex was authored
|
|
19
|
+
// with the /g flag (which would make exec() stateful and
|
|
20
|
+
// produce the wrong results across multiple matches).
|
|
21
|
+
intent.regex.lastIndex = 0;
|
|
22
|
+
const match = intent.regex.exec(input);
|
|
23
|
+
if (match) {
|
|
24
|
+
return { intent, match };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../../src/intent/matcher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,OAAoC,EACpC,KAAa;IAEb,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,6DAA6D;QAC7D,yDAAyD;QACzD,sDAAsD;QACtD,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,EAAC,MAAM,EAAE,KAAK,EAAC,CAAC;QACzB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import { matchIntent } from './matcher.js';
|
|
8
|
+
const noopHandle = async () => null;
|
|
9
|
+
function intent(id, regex) {
|
|
10
|
+
return { id, regex, handle: noopHandle };
|
|
11
|
+
}
|
|
12
|
+
describe('matchIntent', () => {
|
|
13
|
+
it('returns null when no intent matches', () => {
|
|
14
|
+
const intents = [intent('a', /^hello$/), intent('b', /^world$/)];
|
|
15
|
+
expect(matchIntent(intents, 'unrelated')).toBeNull();
|
|
16
|
+
});
|
|
17
|
+
it('matches and exposes capture groups', () => {
|
|
18
|
+
const intents = [intent('install', /^Set up template '(.+)'\.?$/)];
|
|
19
|
+
const result = matchIntent(intents, "Set up template 'marketing-digest'.");
|
|
20
|
+
expect(result).not.toBeNull();
|
|
21
|
+
expect(result?.intent.id).toBe('install');
|
|
22
|
+
expect(result?.match[1]).toBe('marketing-digest');
|
|
23
|
+
});
|
|
24
|
+
it('first match wins when multiple intents would match', () => {
|
|
25
|
+
const intents = [
|
|
26
|
+
intent('first', /^hello (.+)$/),
|
|
27
|
+
intent('second', /^hello world$/),
|
|
28
|
+
];
|
|
29
|
+
const result = matchIntent(intents, 'hello world');
|
|
30
|
+
expect(result?.intent.id).toBe('first');
|
|
31
|
+
expect(result?.match[1]).toBe('world');
|
|
32
|
+
});
|
|
33
|
+
it('treats unanchored regexes literally — author responsibility', () => {
|
|
34
|
+
// "matchIntent" itself doesn't enforce anchoring, but unanchored
|
|
35
|
+
// regexes are surprising. This test documents the behavior:
|
|
36
|
+
// "say hello to me" matches /hello/ even though probably not
|
|
37
|
+
// what the author wanted.
|
|
38
|
+
const intents = [intent('hello', /hello/)];
|
|
39
|
+
const result = matchIntent(intents, 'say hello to me');
|
|
40
|
+
expect(result?.intent.id).toBe('hello');
|
|
41
|
+
});
|
|
42
|
+
it('resets lastIndex on /g-flagged regexes so repeated calls work', () => {
|
|
43
|
+
// Defensive: a global regex with state would otherwise produce
|
|
44
|
+
// null on the second call.
|
|
45
|
+
const intents = [intent('global', /^hello$/g)];
|
|
46
|
+
expect(matchIntent(intents, 'hello')?.intent.id).toBe('global');
|
|
47
|
+
expect(matchIntent(intents, 'hello')?.intent.id).toBe('global');
|
|
48
|
+
});
|
|
49
|
+
it('handles an empty intent list', () => {
|
|
50
|
+
expect(matchIntent([], 'anything')).toBeNull();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=matcher.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.test.js","sourceRoot":"","sources":["../../../src/intent/matcher.test.ts"],"names":[],"mappings":"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"}
|