@fly3366/deepjit 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 +21 -0
- package/README.md +134 -0
- package/README.zh.md +126 -0
- package/cordis.patch.yml +16 -0
- package/dist/collector.d.ts +31 -0
- package/dist/collector.js +258 -0
- package/dist/collector.js.map +1 -0
- package/dist/compiler/optimize.d.ts +30 -0
- package/dist/compiler/optimize.js +47 -0
- package/dist/compiler/optimize.js.map +1 -0
- package/dist/compiler/tiering.d.ts +22 -0
- package/dist/compiler/tiering.js +20 -0
- package/dist/compiler/tiering.js.map +1 -0
- package/dist/config.d.ts +42 -0
- package/dist/config.js +42 -0
- package/dist/config.js.map +1 -0
- package/dist/feedback.d.ts +43 -0
- package/dist/feedback.js +172 -0
- package/dist/feedback.js.map +1 -0
- package/dist/flow-executor.d.ts +46 -0
- package/dist/flow-executor.js +184 -0
- package/dist/flow-executor.js.map +1 -0
- package/dist/genai.d.ts +27 -0
- package/dist/genai.js +57 -0
- package/dist/genai.js.map +1 -0
- package/dist/i18n.d.ts +40 -0
- package/dist/i18n.js +81 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +170 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics.d.ts +28 -0
- package/dist/metrics.js +68 -0
- package/dist/metrics.js.map +1 -0
- package/dist/miner.d.ts +14 -0
- package/dist/miner.js +93 -0
- package/dist/miner.js.map +1 -0
- package/dist/paths.d.ts +13 -0
- package/dist/paths.js +44 -0
- package/dist/paths.js.map +1 -0
- package/dist/status-tool.d.ts +21 -0
- package/dist/status-tool.js +113 -0
- package/dist/status-tool.js.map +1 -0
- package/dist/store.d.ts +122 -0
- package/dist/store.js +317 -0
- package/dist/store.js.map +1 -0
- package/dist/summarizer.d.ts +102 -0
- package/dist/summarizer.js +472 -0
- package/dist/summarizer.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiler "optimize" pass (AOT): validate a candidate flow against the live
|
|
3
|
+
* tool registry and constant-fold literal arguments ahead of time, so the
|
|
4
|
+
* runtime executor does less work and bad flows are rejected at compile time.
|
|
5
|
+
*
|
|
6
|
+
* Mirrors a compiler's middle-end: it never performs side effects, only
|
|
7
|
+
* analysis + rewriting of the IR (the step list).
|
|
8
|
+
*/
|
|
9
|
+
const TEMPLATE_RE = /^\$\{input\.(.+)\}$/;
|
|
10
|
+
function isTemplate(value) {
|
|
11
|
+
return typeof value === 'string' && TEMPLATE_RE.test(value);
|
|
12
|
+
}
|
|
13
|
+
function foldValue(value, stats) {
|
|
14
|
+
if (isTemplate(value)) {
|
|
15
|
+
stats.dynamic++;
|
|
16
|
+
}
|
|
17
|
+
else if (Array.isArray(value)) {
|
|
18
|
+
for (const item of value)
|
|
19
|
+
foldValue(item, stats);
|
|
20
|
+
}
|
|
21
|
+
else if (value && typeof value === 'object') {
|
|
22
|
+
for (const key of Object.keys(value))
|
|
23
|
+
foldValue(value[key], stats);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
stats.folded++; // literal: nothing to resolve at runtime
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function foldArgs(args, stats) {
|
|
30
|
+
for (const key of Object.keys(args))
|
|
31
|
+
foldValue(args[key], stats);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate and partially-evaluate a flow IR. Throws if a step references a
|
|
35
|
+
* tool that does not exist in the live registry (and is not a nested flow).
|
|
36
|
+
*/
|
|
37
|
+
export function optimizeFlow(steps, ctx) {
|
|
38
|
+
const stats = { folded: 0, dynamic: 0 };
|
|
39
|
+
for (const step of steps) {
|
|
40
|
+
if (step.tool !== 'deepjit_flow' && !ctx.toolExists(step.tool)) {
|
|
41
|
+
throw new Error(`AOT: flow references tool not in live registry: "${step.tool}"`);
|
|
42
|
+
}
|
|
43
|
+
foldArgs(step.args ?? {}, stats);
|
|
44
|
+
}
|
|
45
|
+
return { steps, foldedLiterals: stats.folded, dynamicBindings: stats.dynamic };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=optimize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimize.js","sourceRoot":"","sources":["../../src/compiler/optimize.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsBH,MAAM,WAAW,GAAG,qBAAqB,CAAA;AAEzC,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,SAAS,CAAC,KAAc,EAAE,KAA0C;IAC3E,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,OAAO,EAAE,CAAA;IACjB,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAClD,CAAC;SAAM,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC;YAAE,SAAS,CAAE,KAAiC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;IAC3G,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,MAAM,EAAE,CAAA,CAAC,yCAAyC;IAC1D,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAA6B,EAAE,KAA0C;IACzF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,GAAe;IAC/D,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;IACvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,oDAAoD,IAAI,CAAC,IAAI,GAAG,CAAC,CAAA;QACnF,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,OAAO,EAAE,CAAA;AAChF,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiler "tiering" pass: promotion and deoptimization of compiled artifacts,
|
|
3
|
+
* mirroring a JIT's tiered compilation (baseline skill -> optimized flow) and
|
|
4
|
+
* its deopt fallback when optimized code proves unreliable.
|
|
5
|
+
*
|
|
6
|
+
* - Deoptimization: an active flow used enough but failing too often is
|
|
7
|
+
* disabled, handing control back to the agent's own planning.
|
|
8
|
+
* - Promotion: an active skill used often and reliably is returned to the
|
|
9
|
+
* caller so its source pattern can be recompiled as a flow (tier 2).
|
|
10
|
+
*/
|
|
11
|
+
import type { DeepJitStore, ArtifactRow } from '../store.ts';
|
|
12
|
+
export interface TieringConfig {
|
|
13
|
+
deoptMinUses: number;
|
|
14
|
+
deoptMaxSuccessRate: number;
|
|
15
|
+
promoteMinUses: number;
|
|
16
|
+
promoteMinSuccessRate: number;
|
|
17
|
+
}
|
|
18
|
+
export interface TieringResult {
|
|
19
|
+
deopted: string[];
|
|
20
|
+
promote: ArtifactRow[];
|
|
21
|
+
}
|
|
22
|
+
export declare function runTiering(store: DeepJitStore, cfg: TieringConfig): TieringResult;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiler "tiering" pass: promotion and deoptimization of compiled artifacts,
|
|
3
|
+
* mirroring a JIT's tiered compilation (baseline skill -> optimized flow) and
|
|
4
|
+
* its deopt fallback when optimized code proves unreliable.
|
|
5
|
+
*
|
|
6
|
+
* - Deoptimization: an active flow used enough but failing too often is
|
|
7
|
+
* disabled, handing control back to the agent's own planning.
|
|
8
|
+
* - Promotion: an active skill used often and reliably is returned to the
|
|
9
|
+
* caller so its source pattern can be recompiled as a flow (tier 2).
|
|
10
|
+
*/
|
|
11
|
+
export function runTiering(store, cfg) {
|
|
12
|
+
const deopted = [];
|
|
13
|
+
for (const row of store.listDeoptCandidates(cfg.deoptMinUses, cfg.deoptMaxSuccessRate)) {
|
|
14
|
+
store.updateArtifactStatus(row.name, 'disabled');
|
|
15
|
+
deopted.push(row.name);
|
|
16
|
+
}
|
|
17
|
+
const promote = store.listPromoteCandidates(cfg.promoteMinUses, cfg.promoteMinSuccessRate);
|
|
18
|
+
return { deopted, promote };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=tiering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiering.js","sourceRoot":"","sources":["../../src/compiler/tiering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgBH,MAAM,UAAU,UAAU,CAAC,KAAmB,EAAE,GAAkB;IAChE,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACvF,KAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACxB,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,qBAAqB,CAAC,CAAA;IAC1F,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;AAC7B,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Schema from '@deepseek-ai/schemastery';
|
|
2
|
+
export interface DeepJitConfig {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
dbPath: string;
|
|
5
|
+
flushIntervalMs: number;
|
|
6
|
+
flushBatchSize: number;
|
|
7
|
+
maxResultChars: number;
|
|
8
|
+
maxPendingCalls: number;
|
|
9
|
+
minerMaxRows: number;
|
|
10
|
+
transcriptMaxRows: number;
|
|
11
|
+
summarizeIntervalMs: number;
|
|
12
|
+
minIntervalMs: number;
|
|
13
|
+
llmProvider: string;
|
|
14
|
+
llmModel: string;
|
|
15
|
+
minRepeat: number;
|
|
16
|
+
ngramMin: number;
|
|
17
|
+
ngramMax: number;
|
|
18
|
+
argumentAware: boolean;
|
|
19
|
+
compileCandidates: number;
|
|
20
|
+
topK: number;
|
|
21
|
+
minFlowSteps: number;
|
|
22
|
+
minPatternValue: number;
|
|
23
|
+
skillDir: string;
|
|
24
|
+
flowDir: string;
|
|
25
|
+
feedbackMode: 'auto' | 'runtime';
|
|
26
|
+
dryRun: boolean;
|
|
27
|
+
locale: 'auto' | 'en' | 'zh';
|
|
28
|
+
gcEnabled: boolean;
|
|
29
|
+
gcStaleMs: number;
|
|
30
|
+
gcProtectMs: number;
|
|
31
|
+
traceRetentionMs: number;
|
|
32
|
+
patternRetentionMs: number;
|
|
33
|
+
deoptMinUses: number;
|
|
34
|
+
deoptMaxSuccessRate: number;
|
|
35
|
+
qualityMinUses: number;
|
|
36
|
+
minQuality: number;
|
|
37
|
+
promoteMinUses: number;
|
|
38
|
+
promoteMinSuccessRate: number;
|
|
39
|
+
stepTimeoutMs: number;
|
|
40
|
+
flowTimeoutMs: number;
|
|
41
|
+
}
|
|
42
|
+
export declare const Config: Schema<DeepJitConfig>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Schema from '@deepseek-ai/schemastery';
|
|
2
|
+
export const Config = Schema.object({
|
|
3
|
+
enabled: Schema.boolean().default(true),
|
|
4
|
+
dbPath: Schema.string().default(''),
|
|
5
|
+
flushIntervalMs: Schema.number().default(200),
|
|
6
|
+
flushBatchSize: Schema.number().default(200),
|
|
7
|
+
maxResultChars: Schema.number().default(4000),
|
|
8
|
+
maxPendingCalls: Schema.number().default(10_000),
|
|
9
|
+
minerMaxRows: Schema.number().default(20_000),
|
|
10
|
+
transcriptMaxRows: Schema.number().default(2000),
|
|
11
|
+
summarizeIntervalMs: Schema.number().default(10 * 60 * 1000),
|
|
12
|
+
minIntervalMs: Schema.number().default(5 * 60 * 1000),
|
|
13
|
+
llmProvider: Schema.string().default('deepseek-official'),
|
|
14
|
+
llmModel: Schema.string().default(''),
|
|
15
|
+
minRepeat: Schema.number().default(3),
|
|
16
|
+
ngramMin: Schema.number().default(2),
|
|
17
|
+
ngramMax: Schema.number().default(4),
|
|
18
|
+
argumentAware: Schema.boolean().default(false),
|
|
19
|
+
compileCandidates: Schema.number().default(1),
|
|
20
|
+
topK: Schema.number().default(5),
|
|
21
|
+
minFlowSteps: Schema.number().default(2),
|
|
22
|
+
minPatternValue: Schema.number().default(6),
|
|
23
|
+
skillDir: Schema.string().default(''),
|
|
24
|
+
flowDir: Schema.string().default(''),
|
|
25
|
+
feedbackMode: Schema.union(['auto', 'runtime']).default('auto'),
|
|
26
|
+
dryRun: Schema.boolean().default(false),
|
|
27
|
+
locale: Schema.union(['auto', 'en', 'zh']).default('auto'),
|
|
28
|
+
gcEnabled: Schema.boolean().default(true),
|
|
29
|
+
gcStaleMs: Schema.number().default(14 * 24 * 3600 * 1000),
|
|
30
|
+
gcProtectMs: Schema.number().default(24 * 3600 * 1000),
|
|
31
|
+
traceRetentionMs: Schema.number().default(7 * 24 * 3600 * 1000),
|
|
32
|
+
patternRetentionMs: Schema.number().default(7 * 24 * 3600 * 1000),
|
|
33
|
+
deoptMinUses: Schema.number().default(5),
|
|
34
|
+
deoptMaxSuccessRate: Schema.number().default(0.5),
|
|
35
|
+
qualityMinUses: Schema.number().default(5),
|
|
36
|
+
minQuality: Schema.number().default(0),
|
|
37
|
+
promoteMinUses: Schema.number().default(5),
|
|
38
|
+
promoteMinSuccessRate: Schema.number().default(0.8),
|
|
39
|
+
stepTimeoutMs: Schema.number().default(120_000),
|
|
40
|
+
flowTimeoutMs: Schema.number().default(600_000),
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CompiledArtifact } from './summarizer.ts';
|
|
2
|
+
export interface SkillRegistryLike {
|
|
3
|
+
register(skill: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
whenToUse?: string;
|
|
7
|
+
content: string;
|
|
8
|
+
}): () => void;
|
|
9
|
+
get(name: string): Promise<unknown>;
|
|
10
|
+
on(event: 'skills/change', handler: () => void): (() => void) | void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Writes compiled artifacts to the isolated deepjit directory and makes them
|
|
14
|
+
* live in dsh: mechanism A relies on the skill-filesystem provider watching
|
|
15
|
+
* the directory (customSkillDirs in cordis.patch.yml); mechanism B registers
|
|
16
|
+
* the skill at runtime when A is not in effect.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ArtifactFeedback {
|
|
19
|
+
private runtimeRegistrations;
|
|
20
|
+
private watchers;
|
|
21
|
+
private dirs;
|
|
22
|
+
private skills;
|
|
23
|
+
private log;
|
|
24
|
+
constructor(dirs: {
|
|
25
|
+
skillDir: string;
|
|
26
|
+
flowDir: string;
|
|
27
|
+
}, skills: SkillRegistryLike, log: (msg: string) => void);
|
|
28
|
+
publish(artifact: CompiledArtifact): Promise<{
|
|
29
|
+
mode: 'filesystem' | 'runtime';
|
|
30
|
+
filePath: string;
|
|
31
|
+
name: string;
|
|
32
|
+
}>;
|
|
33
|
+
private waitForDiscovery;
|
|
34
|
+
private registerRuntime;
|
|
35
|
+
/** Accept either the prefixed or bare artifact name. */
|
|
36
|
+
private full;
|
|
37
|
+
disable(name: string): void;
|
|
38
|
+
/** Reverse of disable. */
|
|
39
|
+
enable(name: string): void;
|
|
40
|
+
remove(name: string): void;
|
|
41
|
+
private unregisterRuntime;
|
|
42
|
+
disposeAll(): void;
|
|
43
|
+
}
|
package/dist/feedback.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync, renameSync, rmSync, existsSync, readFileSync, watch } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { SKILL_PREFIX } from "./summarizer.js";
|
|
4
|
+
function skillFrontmatter(name, description, whenToUse) {
|
|
5
|
+
const lines = [
|
|
6
|
+
'---',
|
|
7
|
+
`name: ${name}`,
|
|
8
|
+
`description: ${description.replace(/\n/g, ' ')}`,
|
|
9
|
+
];
|
|
10
|
+
if (whenToUse)
|
|
11
|
+
lines.push(`whenToUse: ${whenToUse.replace(/\n/g, ' ')}`);
|
|
12
|
+
lines.push('---', '');
|
|
13
|
+
return lines.join('\n');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Writes compiled artifacts to the isolated deepjit directory and makes them
|
|
17
|
+
* live in dsh: mechanism A relies on the skill-filesystem provider watching
|
|
18
|
+
* the directory (customSkillDirs in cordis.patch.yml); mechanism B registers
|
|
19
|
+
* the skill at runtime when A is not in effect.
|
|
20
|
+
*/
|
|
21
|
+
export class ArtifactFeedback {
|
|
22
|
+
runtimeRegistrations = new Map();
|
|
23
|
+
watchers = new Map();
|
|
24
|
+
dirs;
|
|
25
|
+
skills;
|
|
26
|
+
log;
|
|
27
|
+
constructor(dirs, skills, log) {
|
|
28
|
+
this.dirs = dirs;
|
|
29
|
+
this.skills = skills;
|
|
30
|
+
this.log = log;
|
|
31
|
+
}
|
|
32
|
+
async publish(artifact) {
|
|
33
|
+
const name = `${SKILL_PREFIX}${artifact.name}`;
|
|
34
|
+
if (artifact.type === 'skill') {
|
|
35
|
+
const filePath = path.join(this.dirs.skillDir, name, 'SKILL.md');
|
|
36
|
+
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
37
|
+
writeFileSync(filePath, skillFrontmatter(name, artifact.description, artifact.whenToUse) + (artifact.content ?? ''));
|
|
38
|
+
this.log(`deepjit: wrote skill ${name} -> ${filePath}`);
|
|
39
|
+
return { mode: await this.waitForDiscovery(name, artifact), filePath, name };
|
|
40
|
+
}
|
|
41
|
+
const filePath = path.join(this.dirs.flowDir, `${name}.json`);
|
|
42
|
+
mkdirSync(this.dirs.flowDir, { recursive: true });
|
|
43
|
+
writeFileSync(filePath, JSON.stringify({
|
|
44
|
+
name,
|
|
45
|
+
description: artifact.description,
|
|
46
|
+
whenToUse: artifact.whenToUse,
|
|
47
|
+
steps: artifact.steps,
|
|
48
|
+
createdAt: Date.now(),
|
|
49
|
+
}, null, 2));
|
|
50
|
+
this.log(`deepjit: wrote flow ${name} -> ${filePath}`);
|
|
51
|
+
return { mode: 'filesystem', filePath, name };
|
|
52
|
+
}
|
|
53
|
+
async waitForDiscovery(name, artifact) {
|
|
54
|
+
const timeoutMs = 2000;
|
|
55
|
+
const deadline = Date.now() + timeoutMs;
|
|
56
|
+
const done = new Promise((resolve) => {
|
|
57
|
+
let settled = false;
|
|
58
|
+
const finish = (mode) => {
|
|
59
|
+
if (!settled) {
|
|
60
|
+
settled = true;
|
|
61
|
+
off?.();
|
|
62
|
+
resolve(mode);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const check = async () => {
|
|
66
|
+
try {
|
|
67
|
+
if (await this.skills.get(name))
|
|
68
|
+
return finish('filesystem');
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// not visible yet
|
|
72
|
+
}
|
|
73
|
+
if (Date.now() >= deadline) {
|
|
74
|
+
this.registerRuntime(name, artifact);
|
|
75
|
+
return finish('runtime');
|
|
76
|
+
}
|
|
77
|
+
poll = setTimeout(check, 250);
|
|
78
|
+
};
|
|
79
|
+
const off = this.skills.on('skills/change', () => void check());
|
|
80
|
+
let poll;
|
|
81
|
+
void check();
|
|
82
|
+
return () => {
|
|
83
|
+
if (poll)
|
|
84
|
+
clearTimeout(poll);
|
|
85
|
+
off?.();
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
return done;
|
|
89
|
+
}
|
|
90
|
+
registerRuntime(name, artifact) {
|
|
91
|
+
if (this.runtimeRegistrations.has(name))
|
|
92
|
+
return;
|
|
93
|
+
const content = skillFrontmatter(name, artifact.description, artifact.whenToUse) + (artifact.content ?? '');
|
|
94
|
+
const disposer = this.skills.register({
|
|
95
|
+
name,
|
|
96
|
+
description: artifact.description,
|
|
97
|
+
whenToUse: artifact.whenToUse,
|
|
98
|
+
content,
|
|
99
|
+
});
|
|
100
|
+
this.runtimeRegistrations.set(name, disposer);
|
|
101
|
+
const filePath = path.join(this.dirs.skillDir, name, 'SKILL.md');
|
|
102
|
+
const watcher = watch(path.dirname(filePath), (_event, filename) => {
|
|
103
|
+
if (filename !== 'SKILL.md')
|
|
104
|
+
return;
|
|
105
|
+
const next = this.skills.register({
|
|
106
|
+
name,
|
|
107
|
+
description: artifact.description,
|
|
108
|
+
whenToUse: artifact.whenToUse,
|
|
109
|
+
content: readFileSync(filePath, 'utf8'),
|
|
110
|
+
});
|
|
111
|
+
const old = this.runtimeRegistrations.get(name);
|
|
112
|
+
this.runtimeRegistrations.set(name, next);
|
|
113
|
+
old?.();
|
|
114
|
+
});
|
|
115
|
+
watcher.unref?.();
|
|
116
|
+
this.watchers.set(name, () => {
|
|
117
|
+
watcher.close();
|
|
118
|
+
this.runtimeRegistrations.delete(name);
|
|
119
|
+
this.watchers.delete(name);
|
|
120
|
+
});
|
|
121
|
+
this.log(`deepjit: skill ${name} not discovered via filesystem provider, registered at runtime`);
|
|
122
|
+
}
|
|
123
|
+
/** Accept either the prefixed or bare artifact name. */
|
|
124
|
+
full(name) {
|
|
125
|
+
return name.startsWith(SKILL_PREFIX) ? name : `${SKILL_PREFIX}${name}`;
|
|
126
|
+
}
|
|
127
|
+
disable(name) {
|
|
128
|
+
const full = this.full(name);
|
|
129
|
+
this.unregisterRuntime(full);
|
|
130
|
+
const skillPath = path.join(this.dirs.skillDir, full);
|
|
131
|
+
const flowPath = path.join(this.dirs.flowDir, `${full}.json`);
|
|
132
|
+
if (existsSync(skillPath))
|
|
133
|
+
renameSync(skillPath, `${skillPath}.disabled`);
|
|
134
|
+
if (existsSync(`${skillPath}.disabled`) && existsSync(skillPath))
|
|
135
|
+
rmSync(skillPath, { recursive: true });
|
|
136
|
+
if (existsSync(flowPath))
|
|
137
|
+
renameSync(flowPath, `${flowPath}.disabled`);
|
|
138
|
+
}
|
|
139
|
+
/** Reverse of disable. */
|
|
140
|
+
enable(name) {
|
|
141
|
+
const full = this.full(name);
|
|
142
|
+
const skillPath = path.join(this.dirs.skillDir, full);
|
|
143
|
+
const flowPath = path.join(this.dirs.flowDir, `${full}.json`);
|
|
144
|
+
if (existsSync(`${skillPath}.disabled`) && !existsSync(skillPath)) {
|
|
145
|
+
renameSync(`${skillPath}.disabled`, skillPath);
|
|
146
|
+
}
|
|
147
|
+
if (existsSync(`${flowPath}.disabled`) && !existsSync(flowPath)) {
|
|
148
|
+
renameSync(`${flowPath}.disabled`, flowPath);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
remove(name) {
|
|
152
|
+
const full = this.full(name);
|
|
153
|
+
this.unregisterRuntime(full);
|
|
154
|
+
const skillPath = path.join(this.dirs.skillDir, full);
|
|
155
|
+
const flowPath = path.join(this.dirs.flowDir, `${full}.json`);
|
|
156
|
+
for (const p of [skillPath, `${skillPath}.disabled`, flowPath, `${flowPath}.disabled`]) {
|
|
157
|
+
if (existsSync(p))
|
|
158
|
+
rmSync(p, { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
unregisterRuntime(full) {
|
|
162
|
+
const disposer = this.runtimeRegistrations.get(full);
|
|
163
|
+
if (disposer)
|
|
164
|
+
disposer();
|
|
165
|
+
this.watchers.get(full)?.();
|
|
166
|
+
}
|
|
167
|
+
disposeAll() {
|
|
168
|
+
for (const full of this.runtimeRegistrations.keys())
|
|
169
|
+
this.unregisterRuntime(full);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.js","sourceRoot":"","sources":["../src/feedback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { DeepJitStore } from './store.ts';
|
|
2
|
+
export interface FlowStep {
|
|
3
|
+
tool: string;
|
|
4
|
+
args: Record<string, unknown>;
|
|
5
|
+
onError?: 'stop' | 'continue' | 'retry';
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface FlowTemplate {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
whenToUse?: string;
|
|
12
|
+
steps: FlowStep[];
|
|
13
|
+
}
|
|
14
|
+
export interface StepOutcome {
|
|
15
|
+
index: number;
|
|
16
|
+
tool: string;
|
|
17
|
+
ok: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
summary?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ExecuteFn {
|
|
22
|
+
(input: {
|
|
23
|
+
callId: unknown;
|
|
24
|
+
name: string;
|
|
25
|
+
arguments: Record<string, unknown>;
|
|
26
|
+
agent?: unknown;
|
|
27
|
+
signal: AbortSignal;
|
|
28
|
+
}): Promise<unknown>;
|
|
29
|
+
}
|
|
30
|
+
/** The deepjit_flow tool: replays a compiled flow template with new inputs. */
|
|
31
|
+
export declare class FlowExecutor {
|
|
32
|
+
private flowDir;
|
|
33
|
+
private store;
|
|
34
|
+
private execute;
|
|
35
|
+
private makeCallId;
|
|
36
|
+
private stepTimeoutMs;
|
|
37
|
+
private maxResultChars;
|
|
38
|
+
private log;
|
|
39
|
+
constructor(flowDir: string, store: DeepJitStore, execute: ExecuteFn, makeCallId: (uuid: string) => unknown, stepTimeoutMs: number, maxResultChars: number, log: (msg: string) => void);
|
|
40
|
+
get toolDefinition(): object;
|
|
41
|
+
static readonly MAX_DEPTH = 3;
|
|
42
|
+
run(flowName: string, input: Record<string, unknown>, agent: unknown, signal: AbortSignal, depth?: number): Promise<{
|
|
43
|
+
ok: boolean;
|
|
44
|
+
steps: StepOutcome[];
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { t } from "./i18n.js";
|
|
4
|
+
import { metrics } from "./metrics.js";
|
|
5
|
+
const TEMPLATE_RE = /^\$\{input\.(.+)\}$/;
|
|
6
|
+
function resolveValue(value, input) {
|
|
7
|
+
if (typeof value === 'string') {
|
|
8
|
+
const match = TEMPLATE_RE.exec(value);
|
|
9
|
+
if (match?.[1])
|
|
10
|
+
return getPath(input, match[1]);
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
if (Array.isArray(value))
|
|
14
|
+
return value.map((v) => resolveValue(v, input));
|
|
15
|
+
if (value && typeof value === 'object') {
|
|
16
|
+
const out = {};
|
|
17
|
+
for (const [k, v] of Object.entries(value))
|
|
18
|
+
out[k] = resolveValue(v, input);
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function getPath(obj, dotted) {
|
|
24
|
+
let cur = obj;
|
|
25
|
+
for (const part of dotted.split('.')) {
|
|
26
|
+
if (cur && typeof cur === 'object')
|
|
27
|
+
cur = cur[part];
|
|
28
|
+
else
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return cur;
|
|
32
|
+
}
|
|
33
|
+
function resultSummary(result, maxChars) {
|
|
34
|
+
const r = result;
|
|
35
|
+
if (r?.isError)
|
|
36
|
+
return r.error?.message ?? 'tool failed';
|
|
37
|
+
const content = Array.isArray(r?.content)
|
|
38
|
+
? r.content.filter((b) => b.type === 'text' && typeof b.text === 'string').map((b) => b.text).join('\n')
|
|
39
|
+
: '';
|
|
40
|
+
const value = r?.value === undefined ? '' : JSON.stringify(r.value);
|
|
41
|
+
const text = (content || value || '').trim();
|
|
42
|
+
return text.length <= maxChars ? text : text.slice(0, maxChars) + '…';
|
|
43
|
+
}
|
|
44
|
+
/** The deepjit_flow tool: replays a compiled flow template with new inputs. */
|
|
45
|
+
export class FlowExecutor {
|
|
46
|
+
flowDir;
|
|
47
|
+
store;
|
|
48
|
+
execute;
|
|
49
|
+
makeCallId;
|
|
50
|
+
stepTimeoutMs;
|
|
51
|
+
maxResultChars;
|
|
52
|
+
log;
|
|
53
|
+
constructor(flowDir, store, execute, makeCallId, stepTimeoutMs, maxResultChars, log) {
|
|
54
|
+
this.flowDir = flowDir;
|
|
55
|
+
this.store = store;
|
|
56
|
+
this.execute = execute;
|
|
57
|
+
this.makeCallId = makeCallId;
|
|
58
|
+
this.stepTimeoutMs = stepTimeoutMs;
|
|
59
|
+
this.maxResultChars = maxResultChars;
|
|
60
|
+
this.log = log;
|
|
61
|
+
}
|
|
62
|
+
get toolDefinition() {
|
|
63
|
+
return {
|
|
64
|
+
name: 'deepjit_flow',
|
|
65
|
+
description: 'Execute a JIT-compiled flow template with new arguments. The template was compiled by deepjit from ' +
|
|
66
|
+
'recurring tool workflows. Each step runs through the normal permission system.',
|
|
67
|
+
parameters: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
flow: { type: 'string', description: 'Flow name, e.g. "deepjit-summarize-repo"' },
|
|
71
|
+
args: { type: 'object', description: 'Input values referenced by the flow as ${input.<key>}' },
|
|
72
|
+
},
|
|
73
|
+
required: ['flow'],
|
|
74
|
+
},
|
|
75
|
+
output: {
|
|
76
|
+
schema: { type: 'string' },
|
|
77
|
+
render: (_args, value) => [{ type: 'text', text: String(value) }],
|
|
78
|
+
},
|
|
79
|
+
execute: async (args, exec) => {
|
|
80
|
+
return this.run(args.flow, args.args ?? {}, exec.agent, exec.signal);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
static MAX_DEPTH = 3;
|
|
85
|
+
async run(flowName, input, agent, signal, depth = 0) {
|
|
86
|
+
const artifact = this.store.getArtifact(flowName);
|
|
87
|
+
if (!artifact || artifact.type !== 'flow') {
|
|
88
|
+
throw new Error(t('flow.unknown', { name: flowName }));
|
|
89
|
+
}
|
|
90
|
+
if (artifact.status === 'disabled')
|
|
91
|
+
throw new Error(t('flow.disabled', { name: flowName }));
|
|
92
|
+
const template = JSON.parse(readFileSync(path.join(this.flowDir, `${flowName}.json`), 'utf8'));
|
|
93
|
+
if (!Array.isArray(template.steps) || template.steps.length === 0) {
|
|
94
|
+
throw new Error(t('flow.noSteps', { name: flowName }));
|
|
95
|
+
}
|
|
96
|
+
if (template.steps.some((s) => s.tool === 'deepjit_status')) {
|
|
97
|
+
throw new Error(t('flow.recursive', { name: flowName }));
|
|
98
|
+
}
|
|
99
|
+
const outcomes = [];
|
|
100
|
+
for (let i = 0; i < template.steps.length; i++) {
|
|
101
|
+
if (signal.aborted)
|
|
102
|
+
break;
|
|
103
|
+
const step = template.steps[i];
|
|
104
|
+
const resolvedArgs = resolveValue(step.args ?? {}, input);
|
|
105
|
+
// Nested flow: recurse with the step's args as the child input, depth-limited.
|
|
106
|
+
if (step.tool === 'deepjit_flow') {
|
|
107
|
+
if (depth + 1 > FlowExecutor.MAX_DEPTH) {
|
|
108
|
+
metrics.inc('nested_depth_exceeded');
|
|
109
|
+
outcomes.push({ index: i + 1, tool: step.tool, ok: false, error: t('flow.recursive', { name: flowName }) });
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
const nestedFlow = String(resolvedArgs.flow ?? '');
|
|
113
|
+
const nestedInput = (resolvedArgs.args ?? {});
|
|
114
|
+
try {
|
|
115
|
+
const nested = await this.run(nestedFlow, nestedInput, agent, signal, depth + 1);
|
|
116
|
+
outcomes.push({ index: i + 1, tool: `${step.tool}:${nestedFlow}`, ok: nested.ok, summary: `${nested.steps.length} nested steps` });
|
|
117
|
+
if (!nested.ok && step.onError === 'stop')
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
outcomes.push({ index: i + 1, tool: `${step.tool}:${nestedFlow}`, ok: false, error: err.message });
|
|
122
|
+
if (step.onError === 'stop')
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const timeoutMs = step.timeoutMs ?? this.stepTimeoutMs;
|
|
128
|
+
let attempts = step.onError === 'retry' ? 2 : 0;
|
|
129
|
+
let result;
|
|
130
|
+
let lastError;
|
|
131
|
+
for (let attempt = 0; attempt <= attempts; attempt++) {
|
|
132
|
+
if (signal.aborted)
|
|
133
|
+
break;
|
|
134
|
+
try {
|
|
135
|
+
result = await this.execute({
|
|
136
|
+
callId: this.makeCallId(crypto.randomUUID()),
|
|
137
|
+
name: step.tool,
|
|
138
|
+
arguments: resolvedArgs,
|
|
139
|
+
agent,
|
|
140
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]),
|
|
141
|
+
});
|
|
142
|
+
const r = result;
|
|
143
|
+
if (r?.isError) {
|
|
144
|
+
lastError = r.error?.message ?? `step failed (${step.tool})`;
|
|
145
|
+
if (attempt < attempts) {
|
|
146
|
+
this.log(`deepjit: flow ${flowName} step ${i + 1} failed, retrying (${attempt + 1}/2)`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
lastError = undefined;
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
lastError = err.message;
|
|
157
|
+
if (attempt < attempts)
|
|
158
|
+
continue;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const ok = !lastError;
|
|
163
|
+
outcomes.push({
|
|
164
|
+
index: i + 1,
|
|
165
|
+
tool: step.tool,
|
|
166
|
+
ok,
|
|
167
|
+
error: lastError,
|
|
168
|
+
summary: ok ? resultSummary(result, this.maxResultChars) : undefined,
|
|
169
|
+
});
|
|
170
|
+
if (!ok && step.onError === 'stop')
|
|
171
|
+
break;
|
|
172
|
+
if (!ok && step.onError !== 'continue' && step.onError !== 'retry')
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
const ok = outcomes.every((o) => o.ok) && !signal.aborted;
|
|
176
|
+
this.store.recordOutcome(flowName, ok);
|
|
177
|
+
if (depth === 0) {
|
|
178
|
+
metrics.inc('flow_runs');
|
|
179
|
+
metrics.inc(ok ? 'flow_success' : 'flow_failure');
|
|
180
|
+
}
|
|
181
|
+
return { ok, steps: outcomes };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=flow-executor.js.map
|